Chuyển tới nội dung chính

Chữ ký biểu mẫu HTML

Người mua có thể sửa bất kỳ trường nào của biểu mẫu ngay trong trình duyệt — ví dụ, đặt số tiền thấp hơn. Vì vậy các trường hóa đơn đi trong container đã ký: dịch vụ tính lại chữ ký và, nếu không khớp, không tạo hóa đơn.

Máy chủ của cửa hàng tính chữ ký. Chỉ cặp datasignature hoàn chỉnh mới đi đến trình duyệt.

Ký cái gì

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

HMAC tính trên chuỗi data, không phải trên các byte JSON. Bên nhận xác minh chữ ký với đúng chuỗi được gửi, rồi mới giải mã nó.

Từ đó suy ra không có chuẩn hóa: thứ tự khóa, thụt lề JSON và kiểu thoát Unicode không ảnh hưởng đến chữ ký. Bất kỳ bộ mã hóa JSON chuẩn nào cũng dùng được.

Bộ tham chiếu

Đưa các giá trị này vào mã của bạn và so sánh kết quả.

Khóa bí mật ví dụ:

dvc3khto5WpjEPojZfYJsbJzFEPPVnRa

Số tiền và thời hạn thanh toán dưới dạng số; chuỗi cũng được chấp nhận:

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

Chuỗi data là base64url của các byte đó. Ở đây phần đệm đã được lược bỏ; bên nhận cũng chấp nhận có phần đệm:

eyJwcm9qZWN0SWQiOiJhMWIyYzNkNC01ZTZmLTRhN2ItOGM5ZC0wZTFmMmEzYjRjNWQiLCJhbW91bnRGaWF0IjoxMC41LCJjdXJyZW5jeUZpYXQiOiJVU0QiLCJ0aW1lVG9QYXkiOjEsImRlc2NyaXB0aW9uIjoiT3JkZXIgIzcsIGRlbGl2ZXJ5Iiwic2VydmljZURhdGEiOiJvcmRlci03In0

Chữ ký của chuỗi này với khóa bí mật ở trên:

09628020c47400c9231420450af642adfdb3c246f33e3e12cb8e28f96c2a785e

Với các giá trị này, những ví dụ bên dưới in ra đúng data và chữ ký này. Cùng JSON đó nhưng thêm khóa "output":"errors" ở cuối sẽ cho chuỗi data khác và chữ ký khác.

Nếu data không khớp trong khi JSON trông giống nhau, nguyên nhân là bộ mã hóa JSON: thứ tự khóa khác hoặc khoảng trắng sau dấu phân tách. Bên nhận vẫn chấp nhận container như vậy, nhưng nó sẽ không trùng khớp từng ký tự với tham chiếu.

Ví dụ

<?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";

Các giá trị ví dụ là ASCII, nhưng mã chạy với mọi Unicode mà không cần sửa. PHP và Python mặc định thoát ký tự ngoài ASCII thành \uXXXX, JavaScript gửi UTF-8 thô — bên nhận chấp nhận cả hai.

Hai lỗi thường gặp

Ký JSON thay vì container. HMAC tính trên chuỗi data, tức là trên base64url. Lỗi này biểu hiện như “mọi thứ đều khớp, nhưng chữ ký thì không”.

Dựng lại container sau khi ký. Chỉ cần một byte của data thay đổi, chữ ký mất hiệu lực. Hãy dựng cặp này ở một chỗ duy nhất trong mã của bạn.

Nếu chữ ký không khớp

Đi dọc chuỗi JSON → data → chữ ký; mắt xích đầu tiên lệch khỏi tham chiếu chính là nguyên nhân. Kiểm tra data trước: nó không phụ thuộc vào khóa bí mật.