发布于6小时前6小时 背景 做钱包风控时,很多人只盯着“余额是否被转走”,但实际攻击往往在更早阶段就已经出现信号:异常授权、资金来源污染、交互合约高危、批量小额试探、跨链桥跳转等。尤其在 EVM 链上,攻击者通常不会一上来就清空钱包,而是先通过钓鱼签名、Permit 授权、恶意合约交互拿到可操作权限,再等待合适时机转移资产。 这篇文章主要从链上追踪和钱包风控角度,整理一套比较实用的分析方法:如何识别钱包风险、如何拆解交易行为、如何用脚本做基础自动化扫描。内容偏实战,不讨论泛泛的“不要点钓鱼链接”。 技术分析 1. 钱包风险通常不是单点事件 一个钱包是否高危,不能只看某一笔交易。更合理的做法是综合以下维度: 授权风险:是否对陌生合约做过无限授权,尤其是 ERC20 approve、Permit、Permit2。 资金来源:资金是否来自混币器、被盗地址、钓鱼归集地址或高风险 CEX 充值地址。 交互对象:是否频繁调用未验证合约、短时间新部署合约、代理合约异常升级。 行为模式:是否出现测试转账、小额 gas 补充、批量分发、固定间隔扫钱。 跨链路径:是否通过桥、DEX、聚合器快速切换资产形态,增加追踪成本。 单独一条信号不一定代表被盗,但多条信号叠加时,就应该进入人工复核或自动拦截流程。 2. 授权是最容易被忽视的风险面 很多钱包被盗并不是私钥泄露,而是签过危险授权。典型包括: approve(spender, uint256.max):无限授权给恶意 spender。 increaseAllowance:逐步提高额度,用户不容易察觉。 permit:链下签名,链上由攻击者提交,用户可能没有明确看到 approve 交易。 Permit2:统一授权管理,如果 spender 是高危地址,影响范围会更大。 风控时建议至少维护三个列表: 已知钓鱼 spender 地址列表。 高频被盗资产接收地址列表。 异常合约创建者地址列表。 如果发现用户钱包向这些地址授权过资产,即使资金尚未转走,也应标记为高危。 3. 资金路径追踪不能只看一跳 攻击者常见处理路径: 受害钱包资产转入临时地址 A。 A 将 Token 通过 DEX 换成 ETH、USDT、USDC 等高流动性资产。 资金进入地址 B、C 分散。 部分资金进入跨链桥或交易所充值地址。 如果只看第一跳,很容易漏掉后续归集地址。实际追踪建议至少展开 2 到 3 层,但要控制噪声:DEX Router、桥合约、CEX 热钱包这类中间地址需要特殊处理,不能简单当成最终控制地址。 操作步骤 步骤一:收集目标钱包交易 可以通过节点 RPC、区块浏览器 API、索引服务获取目标地址历史交易。最低要求是拿到: 普通交易:from、to、value、input、timestamp。 ERC20 Transfer 事件。 ERC20 Approval 事件。 内部交易或 trace 数据。 如果只依赖普通交易,会漏掉大量合约内部转账。 步骤二:解析 Approval 事件 ERC20 Approval 事件签名为: Approval(address,address,uint256) keccak256 = 0x8c5be1e5ebec7d5bd14f714f9b5c7f89c5e1e5f0b6f2b8f2b6f2b8f2b6f2b8f2 // 示例不要硬编码,实际应计算或使用标准 topic 实际开发中不要复制网上不确定的 topic,建议直接用 ABI 解码,避免 topic 写错导致漏报。重点关注: owner 是否为目标钱包。 spender 是否为未知合约或高危地址。 value 是否接近 2^256 - 1。 授权后是否很快发生 TransferFrom。 步骤三:分析 Token 流向 对每一笔 ERC20 Transfer,建立图结构: 节点:地址。 边:转账记录,包含 token、amount、tx_hash、block_time。 权重:金额折算、风险标签、时间间隔。 这样可以快速看到资金是否集中流向同一批地址,或者是否出现典型“被盗归集”形态。 步骤四:设置风险评分 可以先从简单规则开始,不一定一开始就上复杂模型。例如: 无限授权给未知合约:+30 spender 命中黑名单:+50 授权后 10 分钟内发生资产转出:+40 资金一跳进入 DEX 换币:+15 两跳内进入已知混币或跨链桥:+25 目标合约创建时间小于 7 天:+20 总分超过阈值后进入告警。实际线上建议保留命中原因,方便人工复核,而不是只给一个分数。 代码示例 下面是一个基础示例:使用 web3.py 查询某个钱包在指定区块范围内的 ERC20 Approval 日志,并标记无限授权。示例偏简化,适合作为风控任务的起点。 from web3 import Web3 from eth_abi import decode RPC_URL = " w3 = Web3(Web3.HTTPProvider(RPC_URL)) wallet = Web3.to_checksum_address("0xYourWalletAddressHere") from_block = 19000000 to_block = 19010000 # Approval(address indexed owner, address indexed spender, uint256 value) approval_topic = Web3.keccak(text="Approval(address,address,uint256)").hex() MAX_UINT256 = 2 ** 256 - 1 RISKY_SPENDERS = { Web3.to_checksum_address("0x0000000000000000000000000000000000000000") } def topic_to_address(topic_hex: str) -> str: return Web3.to_checksum_address("0x" + topic_hex[-40:]) logs = w3.eth.get_logs({ "fromBlock": from_block, "toBlock": to_block, "topics": [approval_topic, "0x" + "0" * 24 + wallet[2:].lower()] }) for log in logs: token = Web3.to_checksum_address(log["address"]) owner = topic_to_address(log["topics"][1].hex()) spender = topic_to_address(log["topics"][2].hex()) value = int.from_bytes(log["data"], byteorder="big") risk_flags = [] if value > MAX_UINT256 // 2: risk_flags.append("INFINITE_APPROVAL") if spender in RISKY_SPENDERS: risk_flags.append("RISKY_SPENDER") if risk_flags: print({ "tx_hash": log["transactionHash"].hex(), "token": token, "owner": owner, "spender": spender, "value": str(value), "risk_flags": risk_flags, "block": log["blockNumber"] }) 这个脚本有几个地方需要注意: 这里只查了指定钱包作为 owner 的 Approval,不包含 Permit 类链下签名授权。 公共 RPC 可能限制日志范围,生产环境建议使用自建节点或稳定索引服务。 只看 Approval 不够,还要关联后续 Transfer 事件判断是否已被利用。 黑名单地址不要硬编码在脚本里,最好放在可更新的数据源中。 进一步的风控实现建议 1. 加入合约画像 对于 spender 或交互合约,可以记录以下信息: 合约是否开源验证。 部署时间和部署者地址。 是否代理合约,implementation 是否近期变更。 是否存在高危函数选择器,例如批量转账、任意调用、delegatecall 包装。 是否与已知钓鱼地址存在资金或部署关联。 一个新部署、未验证、由高危地址部署、短时间收到大量授权的合约,基本应该进入重点监控。 2. 处理 DEX Router 噪声 资金流图里,Uniswap、1inch、0x、Curve 等 Router 会造成大量中间节点。如果不做识别,路径会非常乱。建议: 维护常见 Router 白名单。 把 Router 视为“交易动作”,而不是最终收款方。 解析 Swap 事件,记录换入换出资产。 继续追踪 swap 后资产的接收地址。 这样才能区分正常交易和盗币后的快速洗换。 3. 注意时间窗口 很多盗币路径的时间特征很明显: 授权后几分钟内转出。 转出后立即 swap。 swap 后几笔分散到新地址。 最终在几十分钟内进入桥或交易所。 因此风控规则里一定要加入时间窗口。只看静态地址关系,误报会比较多。 注意事项 不要把所有无限授权都当成盗币。很多正常 DeFi 协议也使用无限授权,关键看 spender 画像和后续行为。 Permit 风险需要单独处理。它可能没有传统 approve 交易,但最终链上仍会出现由攻击者提交的授权或转账动作。 交易所地址要谨慎标注。CEX 热钱包不是攻击者地址,但充值地址可能是资金去向线索。 跨链后不要断点。桥事件通常能提供目标链、接收地址、资产信息,要继续在目标链追踪。 保留证据链。包括 tx hash、block number、日志索引、事件参数,方便后续复核和申诉。 总结 EVM 钱包风控的核心不是简单判断“这个地址是不是黑地址”,而是把授权、交互合约、资金路径、时间窗口放在一起看。实际落地时,可以先从 Approval 监控和 Transfer 路径追踪做起,再逐步加入合约画像、跨链追踪、风险评分和人工复核。 经验上,最有价值的告警通常来自组合信号:陌生合约无限授权 + 短时间资产转出 + DEX 换币 + 多跳分散。单点规则容易误报,组合规则更接近真实攻击路径。 网络请求、日志与边界流量分析示意
5小时前5小时 这个方向挺实用,补充几个我在做 EVM 钱包风险识别时比较常用的落地点,尤其是“授权 + 资金路径 + 告警”怎么串起来。 第一类建议优先监控 `Approval` / `ApprovalForAll`,很多被盗前兆不是资金立刻转走,而是先给了异常合约无限授权。可以把授权额度、spender 风险、合约年龄放一起打分: 风险点: 1. ERC20 Approval value 接近 uint256 max 2. ERC721/ERC1155 setApprovalForAll = true 3. spender 合约创建时间很短 4. spender 没有源码验证,或 bytecode 与已知恶意样本相似 5. spender 近期集中收到多个新钱包授权 6. 授权后短时间内出现 transferFrom / safeTransferFrom 如果自己跑节点,可以直接扫日志,不一定依赖第三方 API。比如用 topic 过滤 ERC20 Approval: from web3 import Web3 w3 = Web3(Web3.HTTPProvider(" APPROVAL_TOPIC = Web3.keccak(text="Approval(address,address,uint256)").hex() logs = w3.eth.get_logs({ "fromBlock": 19000000, "toBlock": "latest", "topics": [APPROVAL_TOPIC] }) for log in logs: owner = "0x" + log["topics"][1].hex()[-40:] spender = "0x" + log["topics"][2].hex()[-40:] value = int(log["data"].hex(), 16) if value > 2**255: print("infinite approval", log["address"], owner, spender, value, log["transactionHash"].hex()) 第二类是资金路径,不建议只看一跳转账。很多地址会经过临时中转、聚合器、跨链桥、DEX,再进混币或交易所。实际分析时我一般分三层: 1-hop:直接收款地址、spender、交互合约 2-hop:中转地址、DEX pair/router、bridge gateway 3-hop:交易所充值地址、混币合约、已知钓鱼团伙地址簇 这里可以维护一个简单的地址标签库,字段不需要太复杂: { "address": "0x...", "chain": "eth", "type": "phishing_spender / drainer / bridge / cex_deposit / mixer / dex_router", "source": "internal_case / public_report / manual_verify", "confidence": 80, "first_seen": 1700000000, "last_seen": 1700000000 } 第三类是告警规则,最好别只靠单点命中,不然误报会很多。可以用组合条件,例如: 高危告警: - 钱包向新合约发起 Approval,且额度为无限授权 - spender 合约创建时间 < 7 天 - 该 spender 在 1 小时内获得超过 10 个不同 owner 授权 - 授权后 10 分钟内出现 transferFrom 转出 中危告警: - 钱包首次与未验证合约交互 - 交互函数选择器命中已知 drainer 常见 selector - 交易 value = 0,但 calldata 很长,且目标不是常见协议合约 有一个细节容易忽略:不要只看成功交易,失败交易也有价值。钓鱼站测试钱包余额、试探 allowance、批量调用失败,这些都能作为前置信号。可以把 failed tx 的 `to`、selector、revert pattern 也纳入画像。 自动化上可以拆成三个队列比较稳: 1. Log Collector: 拉取 Approval / Transfer / contract creation / trace 2. Enrichment: 补充合约年龄、源码验证状态、标签、首次交互时间、历史授权次数 3. Rule Engine: 根据组合规则出告警,写入 ES / ClickHouse / PostgreSQL 如果是蓝队侧接入企业钱包或金库地址,建议把“撤销授权”也做成闭环,不只是告警。比如告警出来后自动生成 revoke 建议: token: 0x... owner: 0x... spender: 0x... current_allowance: unlimited suggest_action: approve(spender, 0) priority: high reason: new spender + infinite approval + associated phishing cluster 最后一点,跨链资产路径要单独处理。很多 EVM 失窃资金会从 ETH / BSC / Polygon 之间走桥,单链上看会像“资金断掉”。桥合约 deposit 事件、目标链 mint/claim 地址要建立映射,否则告警链路会断。这个部分建议至少覆盖常见 bridge router 和 canonical token bridge。总体上,授权风险是前兆,资金路径是溯源,自动化告警要做组合打分,三者放一起效果会比单纯黑名单好很多。
创建帐户或登录后发表意见