回調安全性
本文件概述了我們支付閘道解決方案中可用於保護回調端點的安全機制。當支付事件發生時,我們的系統透過 HTTP 請求傳送回調至客戶端的後端。為了確保這些回調的完整性、真實性和安全性,我們提供了三種互補的安全方法:
- 標頭中的簽名驗證
- IP 白名單
- 透過 API 進行交易驗證
用戶端可根據其安全需求,實施其中一種或多種方法。
1. 標頭簽名驗證
概述
每個回調請求的簽章標頭中都包含一個加密簽章。此簽章是使用 HMAC-SHA256 將要求正文與秘密密鑰串列後產生的。客戶可以驗證此簽章,以確保回調來自我們的付款閘道,且未被竄改。
注意:您可在此找到 API 驗證碼。
簽章產生
簽章的計算方式如下:
- 演算法: HMAC-SHA256
- 輸入: JSON stringified 請求正文
- 鑰匙: 客戶端特定的 apiSecret
- 輸出: 十六進位字串
回調請求格式
- 方法: POST (預設,可設定)
- 標頭 (Headers):
- Content-Type:application/json
- 簽章 (Signature): <hmac-sha256-signature>
- 本體 (Body): 包含付款事件詳細資訊的 JSON 有效負載 (JSON payload containing payment event details)
- 逾時: 5000ms(預設,可設定)
驗證範例
以下是以各種程式語言驗證簽章的實作範例。
- TypeScript
- PHP
- Java
- C#
- Go
- Ruby
using System.Security.Cryptography;
using System.Text;
public class SignatureVerifier
{
public static bool VerifySignature(string body, string signature, string apiSecret)
{
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
{
byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(body));
string computedSignature = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
return computedSignature == signature;
}
}
}
function verifySignature($body, $signature, $apiSecret) {
$computedSignature = hash_hmac('sha256', json_encode($body), $apiSecret);
return hash_equals($computedSignature, $signature);
}
// with apiSecret
String apiSecret = "your apiSecret";
IAPSdk akashicPay = APSdkFactory.createSDK(APEnvironment.Development, otk, apiSecret);
String requestBody = "request body";
String headerSignature = "signature from requestHeader('key: Signature')";
boolean isVerify = akashicPay.verifySignature(
requestBody, headerSignature
);
// with apiSecret
string apiSecret = "your apiSecret";
IApSdk akashicPay = APSdkFactory.createSDK(APEnvironment.Development, otk, apiSecret);
string signature = response.Headers.GetValues("Signature").FirstOrDefault();
string responseBody = await response.Content.ReadAsStringAsync();
return akashicPay.VerifySignature(responseBody, signature);
ap, err := akashicpay.NewAkashicPay(apKey, apL2Address, "Development", "ApiSecretGoesHere")
if err != nil {
// Handle error
}
// Returns true if valid, indicating the callback has not been altered
verified, err := ap.VerifySignature(body, signature)
require 'openssl'
require 'json'
require 'date'
class SignatureVerifier
def initialize(api_secret)
@api_secret = api_secret
end
def verify_signature(body, signature)
raise 'API secret not set' if @api_secret.nil?
begin
sorted_body = sort_keys(body)
serialized = JSON.generate(sorted_body, quirks_mode: true, ascii_only: true)
normalized_signature = signature.strip.gsub(/\A\*?"|"\*?\z/, '')
computed = OpenSSL::HMAC.hexdigest('SHA256', @api_secret, serialized)
computed == normalized_signature
rescue => e
puts "Verification error: #{e.message}"
false
end
end
private
def sort_keys(obj)
case obj
when Array
obj.map { |item| sort_keys(item) }
when Hash
obj.keys.sort.each_with_object({}) do |key, result|
result[key] = sort_keys(obj[key])
end
when Time, Date, DateTime
# Preserve as-is (like JS Date object passed to JSON.stringify)
obj
else
obj
end
end
end
最佳實作
- 安全地儲存 apiSecret (例如,在環境變數中)。
- 使用安全的比較函數 (例如 PHP 中的 hash_equals),以防止定時攻擊。
- 以 401 Unauthorized 回應拒絕缺失或無效簽章的要求。
2. IP 白名單
概述
為了將回呼要求限制為可信來源,我們提供了一組固定的 IP 位址,回呼將從這些 IP 位址發出。用戶端可在防火牆或應用程式邏輯中將這些 IP 列為白名單。請聯繫 AkashicPay 客服中心以獲取需要白名單的 IP 列表。
最佳做法
- 設定您的環境以使用適當的 IP 清單 (測試網路或主網路)。
- 定期檢查我們文件中 IP 清單的更新。
- 記錄並監控來自非白名單 IP 的要求,以進行安全稽核。