मुख्य कंटेंट तक स्किप करें

HTML फ़ॉर्म का हस्ताक्षर

ग्राहक ब्राउज़र में ही फ़ॉर्म का कोई भी फ़ील्ड बदल सकता है — जैसे, कम राशि रख सकता है। इसीलिए इनवॉइस के फ़ील्ड साइन किए हुए कंटेनर में जाते हैं: सेवा हस्ताक्षर दोबारा निकालती है और मेल न खाने पर इनवॉइस नहीं बनाती।

हस्ताक्षर की गणना स्टोर का सर्वर करता है। ब्राउज़र में सिर्फ़ तैयार data और signature की जोड़ी जाती है।

किस पर हस्ताक्षर होता है

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

HMAC की गणना data स्ट्रिंग पर होती है, JSON के बाइट पर नहीं। रिसीवर हस्ताक्षर की जाँच सबमिट हुई स्ट्रिंग पर ज्यों की त्यों करता है, और उसके बाद ही उसे डीकोड करता है।

इससे यह निकलता है कि कोई canonicalization नहीं है: कुंजियों का क्रम, JSON का इंडेंटेशन और 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 स्ट्रिंग और दूसरा हस्ताक्षर देता है।

अगर JSON एक जैसा दिखता है, पर data मेल नहीं खाता, तो कारण 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 डिफ़ॉल्ट रूप से non-ASCII को \uXXXX की तरह एस्केप करते हैं, JavaScript raw UTF-8 भेजता है — रिसीवर दोनों स्वीकार करता है।

दो आम ग़लतियाँ

कंटेनर की जगह JSON पर हस्ताक्षर। HMAC की गणना data स्ट्रिंग पर होती है, यानी base64url पर। यह ग़लती ऐसी दिखती है कि “सब कुछ मेल खाता है, बस हस्ताक्षर नहीं खाता”।

हस्ताक्षर के बाद कंटेनर दोबारा बनाया जाता है। data का एक भी बाइट बदलने पर हस्ताक्षर अमान्य है। जोड़ी अपने कोड में एक ही जगह बनाएँ।

अगर हस्ताक्षर मेल नहीं खाता

JSON → data → हस्ताक्षर की कड़ी पर चलें; जो पहली कड़ी संदर्भ से अलग पड़ती है, वही कारण है। पहले data जाँचें: यह गुप्त कुंजी पर निर्भर नहीं करता।