在前几篇文章,我们分别介绍了交易所钱包系统的整体架构设计、签名机与用户账户生成的方案、用户充值以及用户提现,这篇文章介绍风控,提升系统的安全性。风控的主要目标是防止盗币、欺诈、洗钱以及内部作恶,同时要尽量在不破坏用户体验的前提下拦截高风险行为,提升系统的整体安全性。架构更新在之前的架构
在前几篇文章,我们分别介绍了 交易所钱包系统的整体架构设计、签名机与用户账户生成的方案 、用户充值 以及用户提现, 这篇文章介绍风控,提升系统的安全性。
风控的主要目标是防止盗币、欺诈、洗钱以及内部作恶,同时要尽量在不破坏用户体验的前提下拦截高风险行为,提升系统的整体安全性。
在之前的架构设计中,其实存在一些安全风险:例如 wallet 和 scan 模块都直接读写业务数据库,缺乏统一的权限控制。这种情况下,开发人员可能绕过业务逻辑,直接在数据库中修改敏感数据。
为了解决这个问题,我们可以添加一个数据库网关(DB Gateway),由数据库网关统一控制数据写入。 wallet 模块或 scan 模块需要写入数据时,都通过数据库网关发送请求。 数据库网关单独部署,只允许内网服务访问,从而降低数据库被篡改的风险。
同时,对于高风险操作(如修改用户资金流水、执行用户提现),需要有风控签名确认。
调整后的系统关系如下图所示:
加入风控和数据库网关模块后,可以对数据库的读写权限进行细粒度控制:
ReadOnly
)
Wallet 模块和 scan 模块从数据库读取数据时,可以不经过数据库网关,以提升效率。blocks
、transactions
表)。
除了防火墙控制内网访问外,数据库网关还需验证请求方的签名。withdraws
(取款)和 credits
(资金流水)表的修改。
哪些表属于敏感表,可在配置文件中定义。现在数据读写流程大概是这样的:
sequenceDiagram
participant wallet/scan
participant 风控
participant DB 网关
participant DB
note over wallet/scan,DB: 确保数据库操作安全
DB ->> wallet/scan: 读取数据(直接读、效率优先)
wallet/scan->> DB 网关: 写数据(附带业务签名)
DB 网关 ->> DB: 验证签名后写入
wallet/scan->> 风控: 敏感操作请求风控签名
风控 -->> wallet/scan: 返回风控签名 或 风控建议
wallet/scan->> DB 网关: 提交业务签名 + 风控签名
DB 网关->> DB: 验证双签后写入
签名机拥有独立数据库,私钥仅保存在本机,外部无法访问。 风控系统也有独立数据库,用于存储规则与评估记录,避免业务人员接触内部风控数据,并可根据需要限制风控管理员访问用户钱包数据。
加入风控模块后,每笔提现同样需要风控签名确认。提现流程如下:
sequenceDiagram
participant wallet
participant 风控
participant 签名机
participant RPC 节点
note over wallet, RPC 节点: 确保提现交易安全
wallet->>风控: 请求风控检查,获取签名
风控->>wallet: 返回风控签名或建议
wallet ->> 签名机: 提交业务签名 + 风控签名
签名机-->>wallet: 返回交易签名
wallet->>RPC 节点: 广播交易
风控常见规则包括:
为了配合监控,系统需要实现可审计与可追溯的设计。
我们在风控模块中设计了三张核心表:
风险地址表(address_risk_list):管理风险地址,黑名单地址
风控评估记录表(risk_assessments): 记录评估内容以及评估通过状态
risk_manual_reviews (人工审批记录表):记录所有人工审核操作,包括审核员信息、审核结果等。
完整的表结构见这里。
这里我们主要看一下 风控评估记录表(risk_assessments):
字段名 | 类型 | 约束 | 说明 |
---|---|---|---|
id | INTEGER | PRIMARY KEY AUTOINCREMENT | 主键ID |
operation_id | TEXT | UNIQUE NOT NULL | 操作ID (由业务层生成的UUID) |
table_name | TEXT | 业务表名 (withdrawals/credits),提现评估时为空 | |
record_id | INTEGER | 业务表记录ID (双向关联) | |
action | TEXT | NOT NULL | 操作类型 (insert/update/delete) |
user_id | INTEGER | 关联用户ID | |
operation_data | TEXT | NOT NULL | JSON: 原始操作数据,如果是提现保存交易信息 |
suggest_operation_data | TEXT | JSON: 风控建议的操作数据 | |
suggest_reason | TEXT | 建议原因说明 | |
risk_level | TEXT | NOT NULL | 风险级别: low/medium/high/critical |
decision | TEXT | NOT NULL | 决策: auto_approve/manual_review/deny |
approval_status | TEXT | 审批状态: pending/approved/rejected (仅用于manual_review) | |
reasons | TEXT | JSON: 风险原因数组 | |
risk_signature | TEXT | 风控签名 | |
expires_at | DATETIME | 签名过期时间 | |
created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 更新时间 |
operation_id
: 由业务层生成的UUID,为每一次操作进行编号,这样每一次操作都可以追踪,通知方便以后的日志审计。
action
、operation_data
:记录操作的动作和数据,可以记录对数据库操作的数据,也可以记录交易数据。
suggest_operation_data
: 记录风控的操作建议,例如,风控可能给出建议对一笔存款做冻结处理。
risk_signature
: 风控评估后,对评估的数据(operation_id
、 action
、operation_data
或 suggest_operation_data
、 timestamp
等)签名。
业务层拿到了风控签名后,会加上自己的业务签名,交给数据库网关或签名机,注意这里风控签名和业务签名,所签名的数据是一致的。
我们这里选择了 Ed25519 曲线的签名算法(同 Solana 公链的签名算法),Ed25519的签名和验证速度都非常快。
在任何时候处理签名, 都需要考虑可能的签名重放攻击,因此签名的数据会加入 operation_id
和 timestamp
。
在提现交易中, 签名机除了检查风控和业务签名的有效性外,还会检查签名是否在有效期(例如 1 分钟)。
在 数据库网关中,会使用表 used_operation_ids
维护已使用的 operation_id, 从而防止签名重放攻击。
字段 | 类型 | 说明 |
---|---|---|
id | INTEGER | 主键,自增 |
operation_id | TEXT | 操作ID(UUID),唯一 |
used_at | INTEGER | 使用时间戳(毫秒) |
expires_at | INTEGER | 过期时间戳(毫秒) |
created_at | DATETIME | 创建时间 |
当一些操作风控系统无法独立判断是否通过时,需要进入人工审查, 在人工审查 通过后,业务层需要知道通过状态并继续原操作。可以使用轮询或回调通知两种方式通知业务审核状态,我们这里选择使用回调通知。
例如,以提现进入人工审查为例,执行流程类似这样:
sequenceDiagram
participant 审核员
participant wallet
participant 风控
participant DB
participant RPC
note over 审核员,RPC: 以人工审查提现为例
审核员 ->> 风控: 读取待审核
审核员 ->> 风控: 提交人工审核结构(假设通过)
风控 ->> wallet: 回调钱包、继续提现流程
wallet ->> DB: 选择热钱包 、获取 Nonce 等
wallet ->> 风控 : 再次请求风控签名
wallet ->> RPC : 业务签名 + 风控签名,发起交易
为了让业务层正确关联操作,需要在业务表(如 withdraws
)中添加 operation_id
字段,以便风控通过后,可以通过 operation_id
直接找到对应的提现操作。
当前的风控设计仍是初版,后续可进一步优化:
可配置的风控规则
全链路操作记录可追踪和审计
高频繁操作模式识别、风险智能评估
各业务的通知可使用消息队列
通过本文的风控设计,各模块职责更加明确,且通过签名机制有效提升了安全性:
这种设计既兼顾性能,也保障安全性: 普通数据可直接查询数据库,而敏感操作必须经过双签验证。 即使业务系统被攻破,没有风控签名也无法执行敏感操作。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!