Skip to main content

ลายเซ็นฟอร์ม HTML

ลูกค้าสามารถแก้ไขฟิลด์ใดก็ได้ของฟอร์มจากในเบราว์เซอร์โดยตรง — เช่น ตั้งจำนวนเงินให้ต่ำลง ด้วยเหตุนี้ฟิลด์ของใบแจ้งหนี้จึงถูกส่งในคอนเทนเนอร์ที่เซ็นแล้ว: บริการคำนวณลายเซ็นซ้ำ และหากไม่ตรงกัน จะไม่สร้างใบแจ้งหนี้

เซิร์ฟเวอร์ของร้านค้าเป็นผู้คำนวณลายเซ็น มีเพียงคู่ data และ signature ที่เสร็จแล้วเท่านั้นที่ถูกส่งไปยังเบราว์เซอร์

สิ่งที่ถูกเซ็น

data = base64url(json)
signature = HMAC-SHA256(data, formSecret)

HMAC คำนวณจากสตริง data ไม่ใช่จากไบต์ของ JSON ผู้รับตรวจสอบลายเซ็นกับสตริงที่ส่งมาตามที่เป็น แล้วจึงถอดรหัสในภายหลัง

จึงตามมาว่าไม่มีการทำ canonicalization: ลำดับคีย์ การเยื้องของ JSON และรูปแบบการ escape อักขระ Unicode ไม่มีผลต่อลายเซ็น ตัวเข้ารหัส JSON มาตรฐานตัวใดก็ใช้ได้

ชุดอ้างอิง

นำค่าเหล่านี้ไปใส่ในโค้ดของคุณแล้วเทียบผลลัพธ์

คีย์ลับตัวอย่าง:

dvc3khto5WpjEPojZfYJsbJzFEPPVnRa

จำนวนเงินและกำหนดเวลาชำระเงินเป็นตัวเลข ส่งเป็นสตริงก็ยอมรับเช่นกัน:

{"projectId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","amountFiat":10.5,"currencyFiat":"USD","timeToPay":1,"description":"Order #7, delivery","serviceData":"order-7"}

สตริง data คือ base64url ของไบต์เหล่านั้น ในที่นี้ตัด padding ออกแล้ว ผู้รับยอมรับแบบมี padding ด้วยเช่นกัน:

eyJwcm9qZWN0SWQiOiJhMWIyYzNkNC01ZTZmLTRhN2ItOGM5ZC0wZTFmMmEzYjRjNWQiLCJhbW91bnRGaWF0IjoxMC41LCJjdXJyZW5jeUZpYXQiOiJVU0QiLCJ0aW1lVG9QYXkiOjEsImRlc2NyaXB0aW9uIjoiT3JkZXIgIzcsIGRlbGl2ZXJ5Iiwic2VydmljZURhdGEiOiJvcmRlci03In0

ลายเซ็นของสตริงนี้เมื่อใช้คีย์ลับข้างต้น:

09628020c47400c9231420450af642adfdb3c246f33e3e12cb8e28f96c2a785e

ด้วยค่าเหล่านี้ ตัวอย่างด้านล่างจะพิมพ์ data และลายเซ็นตรงตามนี้ทุกประการ ส่วน JSON เดียวกันที่มีคีย์ "output":"errors" ต่อท้ายจะให้สตริง data และลายเซ็นที่ต่างออกไป

หาก data ไม่ตรงทั้งที่ JSON ดูเหมือนกัน สาเหตุคือตัวเข้ารหัส JSON: ลำดับคีย์ต่างกันหรือมีช่องว่างหลังตัวคั่น ผู้รับจะยอมรับคอนเทนเนอร์แบบนั้น แต่จะไม่ตรงกับชุดอ้างอิงแบบคำต่อคำ

ตัวอย่าง

<?php

function signedContainer(array $fields, string $formSecret): array {
$data = rtrim(strtr(base64_encode(json_encode($fields)), '+/', '-_'), '=');

return [
'data' => $data,
'signature' => hash_hmac('sha256', $data, $formSecret),
];
}

// Test values from the reference set. Before going live,
// replace the secret with the form secret from your project settings
$container = signedContainer([
'projectId' => 'a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d',
'amountFiat' => 10.5,
'currencyFiat' => 'USD',
'timeToPay' => 1,
'description' => 'Order #7, delivery',
'serviceData' => 'order-7',
], 'dvc3khto5WpjEPojZfYJsbJzFEPPVnRa');

echo $container['data'], "\n";
echo $container['signature'], "\n";

ค่าตัวอย่างเป็น ASCII แต่โค้ดทำงานกับ Unicode ใดก็ได้โดยไม่ต้องแก้ไข โดยค่าเริ่มต้น PHP และ Python จะ escape อักขระนอก ASCII เป็น \uXXXX ส่วน JavaScript ส่ง UTF-8 ดิบ — ผู้รับยอมรับทั้งสองแบบ

ข้อผิดพลาดที่พบบ่อยสองข้อ

เซ็น JSON แทนที่จะเซ็นคอนเทนเนอร์ HMAC ต้องคำนวณจากสตริง data นั่นคือจาก base64url ข้อผิดพลาดนี้มีอาการแบบ “ทุกอย่างตรงหมด แต่ลายเซ็นไม่ตรง”

สร้างคอนเทนเนอร์ใหม่หลังจากเซ็นแล้ว หาก data เปลี่ยนไปแม้แต่ไบต์เดียว ลายเซ็นจะใช้ไม่ได้ สร้างคู่ค่านี้ไว้ที่เดียวในโค้ดของคุณ

หากลายเซ็นไม่ตรง

ไล่ตามสายโซ่ JSON → data → ลายเซ็น จุดแรกที่ต่างจากชุดอ้างอิงคือสาเหตุ ให้ตรวจ data ก่อน: ค่านี้ไม่ขึ้นกับคีย์ลับ