Lewati ke konten utama

Tanda tangan formulir HTML

Pembeli dapat mengubah field formulir apa pun langsung di browser—misalnya, memasang jumlah yang lebih kecil. Karena itu field tagihan berjalan dalam kontainer yang ditandatangani: layanan menghitung ulang tanda tangan dan, jika tidak cocok, tidak membuat tagihan.

Server toko yang menghitung tanda tangan. Hanya pasangan data dan signature yang sudah jadi yang dikirim ke browser.

Apa yang ditandatangani

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

HMAC dihitung atas string data, bukan atas byte JSON. Penerima memverifikasi tanda tangan terhadap string yang dikirim apa adanya, baru kemudian mendekodenya.

Artinya tidak ada kanonikalisasi: urutan kunci, indentasi JSON, dan gaya escaping Unicode tidak memengaruhi tanda tangan. Encoder JSON standar apa pun bisa dipakai.

Set acuan

Masukkan nilai-nilai ini ke kode Anda dan bandingkan keluarannya.

Kunci rahasia contoh:

dvc3khto5WpjEPojZfYJsbJzFEPPVnRa

Jumlah dan batas waktu pembayaran sebagai angka; string juga diterima:

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

String data adalah base64url dari byte tersebut. Padding di sini dibuang; penerima juga menerimanya dengan padding:

eyJwcm9qZWN0SWQiOiJhMWIyYzNkNC01ZTZmLTRhN2ItOGM5ZC0wZTFmMmEzYjRjNWQiLCJhbW91bnRGaWF0IjoxMC41LCJjdXJyZW5jeUZpYXQiOiJVU0QiLCJ0aW1lVG9QYXkiOjEsImRlc2NyaXB0aW9uIjoiT3JkZXIgIzcsIGRlbGl2ZXJ5Iiwic2VydmljZURhdGEiOiJvcmRlci03In0

Tanda tangan string ini dengan kunci rahasia di atas:

09628020c47400c9231420450af642adfdb3c246f33e3e12cb8e28f96c2a785e

Dengan nilai-nilai ini, contoh di bawah mencetak data dan tanda tangan persis seperti ini. JSON yang sama dengan kunci "output":"errors" di akhirnya menghasilkan string data yang berbeda dan tanda tangan yang berbeda.

Jika data tidak cocok padahal JSON-nya terlihat sama, penyebabnya adalah encoder JSON: urutan kunci berbeda atau ada spasi setelah pemisah. Penerima tetap menerima kontainer semacam itu, tetapi tidak akan sama persis dengan acuan.

Contoh

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

Nilai contohnya ASCII, tetapi kode ini bekerja dengan Unicode apa pun tanpa perubahan. PHP dan Python secara bawaan meng-escape non-ASCII sebagai \uXXXX, JavaScript mengirim UTF-8 mentah—penerima menerima keduanya.

Dua kesalahan umum

Yang ditandatangani JSON, bukan kontainer. HMAC dihitung atas string data, yaitu atas base64url. Kesalahan ini tampak seperti “semuanya cocok, tetapi tanda tangannya tidak.”

Kontainer dibangun ulang setelah penandatanganan. Jika satu byte saja dari data berubah, tanda tangan tidak sah. Bangun pasangan ini di satu tempat dalam kode Anda.

Jika tanda tangan tidak cocok

Telusuri rantai JSON → data → tanda tangan; mata rantai pertama yang menyimpang dari acuan adalah penyebabnya. Periksa data lebih dulu: nilainya tidak bergantung pada kunci rahasia.