Finix
    Finix
    • Finix API 文档
    • 介绍
    • 签名
    • 验签
    • 印度
      • 收款
        • 创建收款
        • 查询收款状态
        • 收款异步通知
      • 代付
        • 创建代付
        • 查询代付状态
        • 代付异步通知
    • 尼日利亚
      • 收款
        • 创建收款
        • 查询收款状态
        • 收款异步通知
      • 代付
        • 创建代付
        • 查询代付状态
        • 代付异步通知
        • 银行编号
    • 印度尼西亚
      • 收款
        • 创建收款
        • 查询收款状态
        • 收款异步通知
      • 代付
        • 创建代付
        • 查询代付状态
        • 代付异步通知
        • 银行编号
    • 账户余额
      POST
    • USDT汇率
      POST

    验签

    RSA-SHA512 回调验签机制说明#

    一、验签目的#

    为确保 Finix 平台回调通知的真实性、完整性与防止伪造,商户需使用Finix提供的 RSA 公钥结合 SHA512 算法对回调请求头中的 Signature 进行验签。

    二、验签使用场景#

    商户接收到来自 Finix 的回调请求后,需对请求头中的 Signature 字段进行验签,确认数据未被篡改且来源可信。

    三、验签结构与规则#

    平台在回调 HTTP 请求头中附带签名字段 Signature,商户需基于 BODY + Timestamp 计算签名原文,并使用 Finix 公钥进行验证。
    1
    签名算法
    摘要算法:SHA512(Secure Hash Algorithm 512 位)
    加密算法:RSA
    签名算法全称:SHA512withRSA
    签名格式:Base64 编码
    2
    验签原文构造
    签名原文格式如下:
    签名原文 = SHA512(Body JSON 字符串) + Timestamp
    
    注:
    Body:回调请求的原始 JSON 字符串(字段顺序不能变)
    Timestamp:请求头中的 Timestamp 字段,单位为秒
    URL:不参与验签
    例如:
    {"status":"SUCCESS","orderId":"ABC123","amount":100}
    
    计算 SHA512 摘要后:
    09ec4d91b7dd1fce70320b09f3fd7e98cd66efc8f918bb56e98a37c6b179f7d24fc4e43c0a614f8b9e5e95e410af0c0fd9d5f40ad8e38b30a9ad512b48c9c0e7
    
    如果 Timestamp 是:
    1699447297
    
    那么签名原文为:
    09ec4d91b7dd1fce70320b09f3fd7e98cd66efc8f918bb56e98a37c6b179f7d24fc4e43c0a614f8b9e5e95e410af0c0fd9d5f40ad8e38b30a9ad512b48c9c0e71699447297
    
    3
    公钥验签
    使用 Finix 提供的 RSA 公钥对签名原文进行 SHA512withRSA 验签
    将请求头中的 Signature 字段进行 Base64 解码后进行比对
    验签通过,即可确认数据合法

    四、安全性说明#

    Finix 使用其私钥对响应进行签名,商户使用 Finix 公钥验签
    验签成功说明该响应确实来自 Finix 且内容未被篡改
    签名机制确保数据安全、防止中间人攻击和伪造

    五、注意事项#

    签名原文字段顺序必须保持一致
    Body 需要是原始 JSON 字符串(避免缩进、换行、字段顺序调整)
    Base64 解码 Signature 后才能验签
    Timestamp 必须从请求头中读取,与平台签名时间保持一致

    六、代码示例#

    Java
    Python
    PHP
    C#(.NET Core)
    Go
    import java.nio.charset.StandardCharsets;
    import java.security.*;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    
    public class CallbackVerifier {
        public static void main(String[] args) throws Exception {
            String body = "{\"status\":\"SUCCESS\",\"orderId\":\"ABC123\",\"amount\":100}";
            String timestamp = "1699447297";
            String signatureBase64 = "REQUEST_HEADER_SIGNATURE_VALUE";
    
            String bodyHash = sha512Hex(body);
            String stringToVerify = bodyHash + timestamp;
    
            String publicKeyPem = "-----BEGIN PUBLIC KEY-----\nYOUR_FINIX_PUBLIC_KEY_HERE\n-----END PUBLIC KEY-----";
            PublicKey publicKey = loadPublicKey(publicKeyPem);
    
            boolean isValid = verifySignature(publicKey, stringToVerify, signatureBase64);
            System.out.println("Signature valid: " + isValid);
        }
    
        public static String sha512Hex(String data) throws Exception {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] digest = md.digest(data.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) sb.append(String.format("%02x", b));
            return sb.toString();
        }
    
        public static PublicKey loadPublicKey(String pem) throws Exception {
            pem = pem.replace("-----BEGIN PUBLIC KEY-----", "")
                     .replace("-----END PUBLIC KEY-----", "")
                     .replaceAll("\\s+", "");
            byte[] decoded = Base64.getDecoder().decode(pem);
            X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
            return KeyFactory.getInstance("RSA").generatePublic(spec);
        }
    
        public static boolean verifySignature(PublicKey publicKey, String data, String signatureBase64) throws Exception {
            byte[] signatureBytes = Base64.getDecoder().decode(signatureBase64);
            Signature verifier = Signature.getInstance("SHA512withRSA");
            verifier.initVerify(publicKey);
            verifier.update(data.getBytes(StandardCharsets.UTF_8));
            return verifier.verify(signatureBytes);
        }
    }
    
    Previous
    签名
    Next
    创建收款
    Built with