支付风控系统集成:基于 Python 对接天远银行卡风险监测 AP

34 阅读5分钟

1. 引言:构建支付系统的“安全层”

在电商结算、信贷审核或第三方支付场景中,账户合规性校验是保障业务安全的基础环节。对于开发者而言,如何在毫秒级响应内识别异常银行卡状态,并确保传输过程中的数据隐私安全,是一个典型的工程挑战。

本文将以 JRZQ0B6Y 风险监测接口 为例,从纯技术角度解析如何使用 Python 实现符合 AES-128-CBC 标准的加密签名请求,并对返回的 JSON 数据进行类型清洗与解析,为您的支付网关构建一道技术防线。

2. 技术难点:AES-128-CBC 与 Base64 组合加密

为了保障敏感数据的传输安全,多数金融级接口都要求对请求体进行加密。本例中的接口要求如下:

  • 加密算法:AES-128
  • 模式:CBC (Cipher Block Chaining)
  • 填充:PKCS7
  • 传输:Base64 编码 + 随机 IV (初始化向量)

这种组合在 Python 的标准库中并非开箱即用,我们需要借助 pycryptodome 库来手动实现。

2.1 环境依赖

Bash

pip install pycryptodome requests

2.2 核心工具类封装

以下代码封装了通用的加解密逻辑,解决了 IV 拼接和 PKCS7 填充的细节问题。

Python

import requests
import json
import base64
import time
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

class RiskCheckClient:
    def __init__(self, access_id, access_key_hex):
        # 示例接口地址
        self.api_url = "https://api.tianyuanapi.com/api/v1/JRZQ0B6Y"
        self.access_id = access_id
        # 将16进制密钥转换为字节串
        self.access_key = bytes.fromhex(access_key_hex)

    def _encrypt(self, plain_dict):
        """
        AES-CBC 加密流程:
        1. 生成随机 IV (16字节)
        2. 数据 JSON 序列化 + PKCS7 填充
        3. 加密 -> 拼接 IV -> Base64 编码
        """
        iv = get_random_bytes(16)
        cipher = AES.new(self.access_key, AES.MODE_CBC, iv)
        
        data_bytes = json.dumps(plain_dict).encode('utf-8')
        ciphertext = cipher.encrypt(pad(data_bytes, AES.block_size))
        
        return base64.b64encode(iv + ciphertext).decode('utf-8')

    def _decrypt(self, encrypted_b64):
        """
        解密流程:Base64解码 -> 分离IV -> AES解密 -> 去除填充
        """
        try:
            encrypted_bytes = base64.b64decode(encrypted_b64)
            iv = encrypted_bytes[:16] # 提取前16字节 IV
            ciphertext = encrypted_bytes[16:]
            
            cipher = AES.new(self.access_key, AES.MODE_CBC, iv)
            decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
            return json.loads(decrypted_data.decode('utf-8'))
        except Exception as e:
            print(f"解密数据异常: {e}")
            return None

    def query_card_status(self, name, id_card, mobile, bank_card):
        # 1. 构造业务参数
        params = {
            "name": name,
            "id_card": id_card,
            "mobile_no": mobile,
            "bank_card": bank_card
        }
        
        # 2. 加密 payload
        encrypted_data = self._encrypt(params)
        
        # 3. 构造请求
        headers = {"Access-Id": self.access_id}
        payload = {"data": encrypted_data}
        # 添加时间戳防止重放
        timestamp = int(time.time() * 1000)
        
        try:
            resp = requests.post(f"{self.api_url}?t={timestamp}", headers=headers, json=payload)
            res_json = resp.json()
            
            if res_json.get("code") == 0:
                # 4. 解密响应内容
                return self._decrypt(res_json.get("data"))
            else:
                print(f"请求响应码异常: {res_json.get('code')} - {res_json.get('message')}")
                return None
        except Exception as e:
            print(f"网络请求失败: {e}")
            return None

# --- Main 调用示例 ---
if __name__ == "__main__":
    # 请替换为测试用的 Access-Id 和 Key
    client = RiskCheckClient("YOUR_ID", "YOUR_HEX_KEY")
    
    result = client.query_card_status(
        name="测试用户", 
        id_card="11010119900101xxxx", 
        mobile="13800000000", 
        bank_card="622202xxxx"
    )
    
    if result:
        print("接口返回数据:", json.dumps(result, indent=2, ensure_ascii=False))

3. 数据解析与状态清洗

接口返回的数据结构通常较为扁平,为了便于业务逻辑判断,我们需要理解各字段的含义。以下是基于 API 文档整理的字段映射表:

原始字段类型技术含义建议处理方式
caseRelatedString关联异常案件若值为 "1",建议标记为 High Risk,阻断流程。
fraudTransString关联异常交易若值为 "1",建议结合业务场景进行二次验证。
badCardHolderString持卡人状态异常若值为 "1",建议转人工复审。
onlineBlackString线上渠道风险若值为 "1",建议限制线上支付额度。

开发者注意:API 返回的标识位通常是字符串类型的 "1" (命中) 和 "0" (未命中)。在 Python 中进行条件判断时,切勿直接使用布尔值转换(因为非空字符串均为 True),应显式判断:

Python

# 正确的判断逻辑
is_risky = result.get("caseRelated") == "1" or result.get("fraudTrans") == "1"

if is_risky:
    print("触发风控拦截策略")
else:
    print("账户状态正常,放行")

4. 场景应用总结

通过上述 Python 代码,我们将复杂的 AES 加密逻辑封装成了简单的 query_card_status 方法。在实际的支付网关或风控中台开发中,这种设计模式有以下优势:

  1. 安全性:所有敏感参数(身份证、卡号)均在本地加密后传输,符合 HTTPS + AES 双重加密标准。
  2. 解耦性:加解密逻辑与业务逻辑分离,便于后续维护。
  3. 扩展性:基于该结构,可以轻松扩展其他风险查询接口。

附录:技术规范与合规提示

在集成此类数据服务时,请开发者务必关注代码规范与数据合规:

  1. 密钥安全管理

    • 严禁将 Access-IdAccess-Key 硬编码在代码仓库中。
    • 建议使用环境变量(Environment Variables)或 KMS 服务进行管理。
  2. 隐私保护与授权

    • 最小化原则:仅在业务必要环节(如绑卡、提现)调用接口。
    • 用户授权:在进行任何风险数据查询前,必须确保已获得用户的明确授权(如隐私协议勾选)。
    • 数据脱敏:日志中禁止打印明文的身份证号与银行卡号,建议仅打印掩码后的脱敏数据。