簽名算法
1 加密(Encrypt)
步驟
- 取得當前時間戳
${timestamp} - 將
${timestamp}與請求體組合成新的字串$content:- 若 HTTP 方法為 POST,請求體為 JSON 文本
- 若 HTTP 方法為 GET,請求體為「未轉義的查詢字串」
- 範例:
name=foo&age=18為有效格式 name%3dfoo%26age%3d18為無效格式
- 範例:
- 使用 SHA256 與 PKCS1V15、1024-bit RSA 對
$content進行簽名 - 將簽名後的資料以 Base64 編碼
範例
以下為簽名示例。時間戳為 1751441054,RSA 金鑰為:
-----以下金鑰對僅供測試使用-----
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOFSnhqtu40TOtok+yXeB+O76PXb/VAJU4Yih6hViOdSGd7imWmCSZyP
psl3TmLhUoB+rTzYDdYrlYYng6cVn6yUhxjpMWD4Qp5K4GzjvUM0f+AxlKYMj8OQ
AgDPmZG1a5ydFrje4PLytC7sUw3GP4TTk8xg6iMHmYPdRDv7AEWdAgMBAAE=
-----END RSA PUBLIC KEY----------BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDhUp4arbuNEzraJPsl3gfju+j12/1QCVOGIoeoVYjnUhne4plp
gkmcj6bJd05i4VKAfq082A3WK5WGJ4OnFZ+slIcY6TFg+EKeSuBs471DNH/gMZSm
DI/DkAIAz5mRtWucnRa43uDy8rQu7FMNxj+E05PMYOojB5mD3UQ7+wBFnQIDAQAB
AoGBAIqpeCi83516xw32EiSEleBdBIlA34vAoYj7ePZr5PtN+CPE2Von1rslYCO9
axzIwyfWTTATWbiCS9sqOAe78+1t3shU0ryXelWQ95LOdiMp0ZvU3ya6MzSVuiuL
6gOQYu8kzRqCzqvyMNdAHFMmP0iESefYegaiU46yQo2ZZAtVAkEA/N6gl4tYJBef
e/Gxi7qhuIKz0mvfA/yieRuiVhFb25oJaagU6hBuzegmbs45hh+n4bw8AA9k0bvi
3IBIdV/CbwJBAOQcsOPf+lrs4PEJYUQ8/eqiG7tgIUeXxuerfPYMAzvJ7EU1u72o
/5V9zdim+hPq+9cvsqO7dkJx+cEpgwHKzrMCQQDoYqArJP/Hi34hpaiIxOdCbbtc
MY4uV8noiqDRf/pvAkyMMM+nm5p42FQZmKP8wrLCHP72/y6kIIsIIUx1sZ85AkEA
15eWR4jEoXMIFkd7Onc6tKuJ8kokqfl08DhP3mv0EmoBeFgUnGhBRxSjnIQUDwck
Bnj6KW1fk+UM29dUDjmTqQJBAITyP16eBWjlzcgaxoT2d/d7S7AXvgCxCzRRi5ph
IavMyjrhDKyBGZ0mI6eoREaC4bxl31RRkYtg9mNeU3TxsBM=
-----END RSA PRIVATE KEY-----
JSON 請求體
{
"merchantId": "bybit",
"clientId": "xx",
"paymentType": "E_COMMERCE",
"merchantTradeNo": "8751738a-97a4-49da-8b64-185ffcb98a7a",
"payId": "01JXWP4XK4ZRVYD3HT9PD52KCD",
"status": "PAY_SUCCESS",
"amount": "1.23",
"currency": "USDT",
"currencyType": "crypto",
"createTime": 1750088344,
"paymentTime": 1750088344,
"finishTime": 1750088344,
"customer": {
"external_user_id": "123",
"user_name": "tester",
"register_time": "1750088344",
"kyc_country": "HK",
"uid": "foo"
}
}
具體簽名步驟
- 取得當前時間戳:
1751441054
- 將
${timestamp}與請求體組合為新字串$content:
1751441054{"merchantId":"bybit","clientId":"xx","paymentType":"E_COMMERCE","merchantTradeNo":"8751738a-97a4-49da-8b64-185ffcb98a7a","payId":"01JXWP4XK4ZRVYD3HT9PD52KCD","status":"PAY_SUCCESS","amount":"1.23","currency":"USDT","currencyType":"crypto","createTime":1750088344,"paymentTime":1750088344,"finishTime":1750088344,"customer":{"external_user_id":"123","user_name":"tester","register_time":"1750088344","kyc_country":"HK","uid":"foo"}}
- 使用 SHA256 與 PKCS1V15、1024-bit RSA 對
$content進行簽名。 - 將簽名後的位元資料以 Base64 編碼:
vOyN+NnfWppnhxS6y1D+CAllj6Z/3np1Tm+nrt16e/EDl4VZjU2sVPSS/cBcf5Hy/jBarA8Y7yrvYqJonJAsAZcFKu9twW2XWyMbURC63Iumh5gkAE9UEx4/irpX4W6KXhqc2+7wc1tapC5zfVWRMIQ5Dh+7VscxLY+/WjKb/Vw=
2 解密(Decrypt)
步驟
- 從請求標頭中取得
timestamp與signature。 - 取得請求體:
- 若 HTTP 方法為 POST,請求體為 JSON 文本。
- 若 HTTP 方法為 GET,請求體為「未轉義的查詢字串」。
- 將
${timestamp}與回應體組合成新字串$content。 - 將
signature由 Base64 解碼為資料。 - 使用 SHA256 對
$content字串進行雜湊,並用 PKCS1V15、1024-bit RSA 驗證簽名。
範例
給定以下資料:
vOyN+NnfWppnhxS6y1D+CAllj6Z/3np1Tm+nrt16e/EDl4VZjU2sVPSS/cBcf5Hy/jBarA8Y7yrvYqJonJAsAZcFKu9twW2XWyMbURC63Iumh5gkAE9UEx4/irpX4W6KXhqc2+7wc1tapC5zfVWRMIQ5Dh+7VscxLY+/WjKb/Vw=
時間戳為 1751441054,RSA 金鑰為:
-----以下金鑰對僅供測試使用-----
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOFSnhqtu40TOtok+yXeB+O76PXb/VAJU4Yih6hViOdSGd7imWmCSZyP
psl3TmLhUoB+rTzYDdYrlYYng6cVn6yUhxjpMWD4Qp5K4GzjvUM0f+AxlKYMj8OQ
AgDPmZG1a5ydFrje4PLytC7sUw3GP4TTk8xg6iMHmYPdRDv7AEWdAgMBAAE=
-----END RSA PUBLIC KEY----------BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDhUp4arbuNEzraJPsl3gfju+j12/1QCVOGIoeoVYjnUhne4plp
gkmcj6bJd05i4VKAfq082A3WK5WGJ4OnFZ+slIcY6TFg+EKeSuBs471DNH/gMZSm
DI/DkAIAz5mRtWucnRa43uDy8rQu7FMNxj+E05PMYOojB5mD3UQ7+wBFnQIDAQAB
AoGBAIqpeCi83516xw32EiSEleBdBIlA34vAoYj7ePZr5PtN+CPE2Von1rslYCO9
axzIwyfWTTATWbiCS9sqOAe78+1t3shU0ryXelWQ95LOdiMp0ZvU3ya6MzSVuiuL
6gOQYu8kzRqCzqvyMNdAHFMmP0iESefYegaiU46yQo2ZZAtVAkEA/N6gl4tYJBef
e/Gxi7qhuIKz0mvfA/yieRuiVhFb25oJaagU6hBuzegmbs45hh+n4bw8AA9k0bvi
3IBIdV/CbwJBAOQcsOPf+lrs4PEJYUQ8/eqiG7tgIUeXxuerfPYMAzvJ7EU1u72o
/5V9zdim+hPq+9cvsqO7dkJx+cEpgwHKzrMCQQDoYqArJP/Hi34hpaiIxOdCbbtc
MY4uV8noiqDRf/pvAkyMMM+nm5p42FQZmKP8wrLCHP72/y6kIIsIIUx1sZ85AkEA
15eWR4jEoXMIFkd7Onc6tKuJ8kokqfl08DhP3mv0EmoBeFgUnGhBRxSjnIQUDwck
Bnj6KW1fk+UM29dUDjmTqQJBAITyP16eBWjlzcgaxoT2d/d7S7AXvgCxCzRRi5ph
IavMyjrhDKyBGZ0mI6eoREaC4bxl31RRkYtg9mNeU3TxsBM=
-----END RSA PRIVATE KEY-----
具體驗證步驟
- 從請求標頭取得
timestamp與signature:
timestamp = 1751441054
signature = vOyN+NnfWppnhxS6y1D+CAllj6Z/3np1Tm+nrt16e/EDl4VZjU2sVPSS/cBcf5Hy/jBarA8Y7yrvYqJonJAsAZcFKu9twW2XWyMbURC63Iumh5gkAE9UEx4/irpX4W6KXhqc2+7wc1tapC5zfVWRMIQ5Dh+7VscxLY+/WjKb/Vw=
- 取得請求體(POST:JSON 文本;GET:未轉義查詢字串):
{"merchantId":"bybit","clientId":"xx","paymentType":"E_COMMERCE","merchantTradeNo":"8751738a-97a4-49da-8b64-185ffcb98a7a","payId":"01JXWP4XK4ZRVYD3HT9PD52KCD","status":"PAY_SUCCESS","amount":"1.23","currency":"USDT","currencyType":"crypto","createTime":1750088344,"paymentTime":1750088344,"finishTime":1750088344,"customer":{"external_user_id":"123","user_name":"tester","register_time":"1750088344","kyc_country":"HK","uid":"foo"}}
- 將
${timestamp}與回應內容組合為新字串$content:
1751441054{"merchantId":"bybit","clientId":"xx","paymentType":"E_COMMERCE","merchantTradeNo":"8751738a-97a4-49da-8b64-185ffcb98a7a","payId":"01JXWP4XK4ZRVYD3HT9PD52KCD","status":"PAY_SUCCESS","amount":"1.23","currency":"USDT","currencyType":"crypto","createTime":1750088344,"paymentTime":1750088344,"finishTime":1750088344,"customer":{"external_user_id":"123","user_name":"tester","register_time":"1750088344","kyc_country":"HK","uid":"foo"}}
- 將
signature由 Base64 解碼為位元資料。 - 使用 SHA256 對上述字串內容進行雜湊,並基於 PKCS1V15、1024-bit RSA 驗證簽名。