Sign in
บทนำ/การยืนยันตัวตน

การยืนยันตัวตนและการลงลายเซ็นคำขอ

ลงลายเซ็นคำขอ API ด้วย HMAC-SHA256 โดยใช้ project UUID และ API key ของคุณ

คำขอ API ทุกรายการ (ยกเว้น Webhook ขาเข้า) ต้องมี project UUID และลายเซ็นคำขอแนบมาด้วย ลายเซ็นเป็นการพิสูจน์ว่าคำขอมาจากคุณจริงและไม่มีใครแก้ไขระหว่างทาง

API key

2328.io ใช้ คีย์สองชุด ที่ใช้อัลกอริทึมการลงลายเซ็นเดียวกัน แต่ครอบคลุม endpoint ต่างกัน:

Keyใช้สำหรับ
API keyการชำระเงิน, กระเป๋าเงินคงที่, ยอดคงเหลือ, อัตราแลกเปลี่ยน และการตรวจสอบ Webhook ของการชำระเงิน / กระเป๋าเงินคงที่
Payout API keyendpoint /v1/payout/* ทั้งหมด และการตรวจสอบ Webhook ของการถอน

คีย์ทั้งสองอยู่ในการตั้งค่าโปรเจกต์ของคุณที่ 2328.io ตัวอย่างด้านล่างจะใช้คำว่า "API key" แบบรวม ๆ — ให้แทนที่ด้วยคีย์ที่ถูกต้องตาม endpoint ที่คุณกำลังเรียกใช้

ห้าม สลับใช้คีย์ทั้งสอง: การลงลายเซ็นคำขอถอนด้วย API key ปกติ (หรือคำขอชำระเงินด้วย Payout key) จะคืนข้อผิดพลาดเรื่องลายเซ็น

Header ที่จำเป็น

HeaderTypeRequiredDescription
Content-Typestringyesต้องเป็น application/json เสมอ
projectstringyesproject UUID ของคุณ
signstringyesลายเซ็น HMAC-SHA256 ของคำขอ คำนวณด้วย API key ของคุณ
User-Agentstringใช่ระบุแอปพลิเคชันของคุณ (เช่น MyShop/1.4 (+https://myshop.example)) คำขอที่ไม่มี User-Agent อาจถูกบล็อก

ลายเซ็นทำงานอย่างไร

คิดว่าลายเซ็นเป็นลายนิ้วมือของ body คำขอ มันถูกสร้างขึ้นโดย:

  1. แปลง body เป็น JSON (กระชับ — ไม่มีช่องว่างเกิน)
  2. เข้ารหัส JSON นั้นด้วย Base64 ขั้นตอนนี้ทำให้อินพุตเป็นมาตรฐานเดียวกันในทุกภาษา — เมื่อกลายเป็น ASCII ล้วนแล้ว ทุกภาษาจะให้ไบต์เดียวกันสำหรับ HMAC
  3. คำนวณ HMAC-SHA256 ของสตริง Base64 โดยใช้ API key ของคุณ จากนั้นแปลงผลลัพธ์เป็น hex ตัวพิมพ์เล็ก

สำหรับคำขอแบบ GET และคำขอประเภทอื่น ๆ ที่ไม่มี body ให้ลงลายเซ็นสตริงว่างแทน JSON

ลายเซ็นของสตริงว่างเป็นค่าคงที่สำหรับ API key ใด ๆ คุณสามารถ cache ไว้ได้หากเรียก GET หลายครั้ง

การ implement

PHP
<?php
function apiSign(array $data, string $apiKey): string {
    $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $base64 = base64_encode($json);
    return hash_hmac('sha256', $base64, $apiKey);
}

คำขอที่ไม่มี body (GET)

สำหรับคำขอที่ไม่มี body (เช่น GET /v1/payout/status/{uuid}) ให้ลงลายเซ็นสตริงว่าง:

Shell
SIGN=$(printf '' | openssl dgst -sha256 -hmac "$API_KEY" -hex | awk '{print $NF}')

ตัวอย่างคำขอแบบเต็ม

Shell
curl -X POST https://api.2328.io/api/v1/payment \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyShop/1.0 (+https://myshop.example)" \
  -H "project: YOUR_PROJECT_UUID" \
  -H "sign: YOUR_HMAC_SIGNATURE" \
  -d '{"amount":"100.00","currency":"USD","order_id":"ORDER-123"}'

ห้ามเปิดเผย API key ของคุณในโค้ดฝั่ง client เด็ดขาด ให้ลงลายเซ็นคำขอบน backend หาก API key รั่วไหล ใครก็ตามจะเข้าถึงบัญชีผู้ค้าของคุณได้อย่างเต็มรูปแบบ

การตรวจสอบลายเซ็น Webhook

เมื่อ 2328.io ส่ง Webhook มาให้คุณ จะใช้อัลกอริทึมเดียวกันแต่ทำกลับด้าน:

  1. ดึงฟิลด์ sign ออกจาก payload
  2. เข้ารหัสฟิลด์ที่เหลือเป็น JSON (กระชับ ไม่มีช่องว่าง)
  3. เข้ารหัสสตริงนั้นด้วย Base64
  4. คำนวณ HMAC-SHA256 ด้วยคีย์ที่เหมาะสม
  5. เปรียบเทียบกับ sign ที่ได้รับโดยใช้การเปรียบเทียบแบบ constant-time (hash_equals, crypto.timingSafeEqual, hmac.compare_digest, subtle.ConstantTimeCompare, OpenSSL.fixed_length_secure_compare)

คีย์ที่ใช้ลงลายเซ็นขึ้นกับแหล่งของ Webhook:

WebhookKey to verify with
Webhook การชำระเงิน / กระเป๋าเงินคงที่ (/v1/payment, /v1/static-wallet)API key
Webhook การถอน (/v1/payout)Payout API key

ข้อผิดพลาดที่พบบ่อยในการตรวจสอบ ตัวเข้ารหัส JSON ของคุณต้องสร้าง ไบต์ที่เหมือนกันทุกประการ กับที่ผู้ส่งสร้างขึ้น — มิฉะนั้น Base64 จะต่างกันและลายเซ็นจะไม่ตรงกัน

  • Go: ใช้ json.NewEncoder พร้อม SetEscapeHTML(false) ค่าเริ่มต้นของ json.Marshal จะ escape <, >, & เป็น < และทำให้ลายเซ็นเสียหาย
  • Python: ส่ง ensure_ascii=False ไปยัง json.dumps ถ้าไม่ส่ง ตัวอักษรที่ไม่ใช่ ASCII (ซีริลลิก จีน …) จะถูก escape เป็น \uXXXX
  • JSON แบบกระชับ: ห้ามมีช่องว่างระหว่างฟิลด์ (separators=(",", ":") ใน Python)
  • ลำดับฟิลด์ (Go): map[string]any ธรรมดาจะสุ่มลำดับคีย์เมื่อเข้ารหัสใหม่ ให้ใช้ json.RawMessage, struct ที่มีลำดับแน่นอน หรือลบ sign ออกจากไบต์ดิบ

หากการตรวจสอบยังคงล้มเหลว ให้รัน apiSign กับ payload ด้วยตัวเอง — ต้องสร้างสตริงเลขฐานสิบหกเดียวกันกับ sign ที่ได้รับ

ลายเซ็นที่ถูกต้องไม่สามารถป้องกันการ replay ได้ มันเพียงพิสูจน์ว่า webhook มาจาก 2328.io เท่านั้น — มันไม่ได้หยุดผู้โจมตีจากการส่ง webhook ที่ถูกดักจับไว้ซ้ำในภายหลัง ตรวจสอบ idempotency โดย uuid เสมอ (หรือ txid สำหรับ static wallets) ก่อนบันทึกเงินเข้าบัญชี ปฏิเสธด้วย HTTP 401 หากลายเซ็นหายไปหรือไม่ถูกต้อง

ตัวอย่างโค้ดเต็มอยู่ที่ Webhook Notifications การจัดการการลองใหม่และกฎ idempotency อยู่ใน แนวปฏิบัติที่ดี