NodeJS全栈WEB3面试题——P6安全与最佳实践

发布于:2025-06-03 ⋅ 阅读:(78) ⋅ 点赞:(0)

🔐 6.1 如何防范重放攻击、私钥泄露、钓鱼签名?

✅ 重放攻击(Replay Attack)防范:
  • 引入 nonce:每次登录或交易签名都携带唯一 nonce;

  • 链 ID 检查:在签名中加入特定链 ID,防止跨链重放;

  • 使用 EIP-712 签名结构:结构化签名防止签名滥用。

✅ 私钥泄露防范:
  • 从不把私钥写入前端代码或硬盘明文保存

  • 后端钱包使用冷钱包或 HSM 服务(如 AWS KMS, Fireblocks)

  • 使用环境变量加密存储助记词或私钥,部署中使用 .env + vault

  • 限制私钥操作权限,冷热钱包分离

✅ 钓鱼签名防范:
  • 签名前显示明确信息说明(如“登录授权而非转账”);

  • 使用 EIP-712 结构化数据签名,避免用户签不明数据;

  • 前端签名提示加上网站来源(如 yourapp.com)+ 描述;


6.2 什么是“前置运行攻击”(Front-running)?怎么防御?

✅ 定义:

Front-running 是攻击者监听 mempool,抢在用户交易之前提交相同或对其有利的交易(如抢先购买 NFT、调整价格、抢矿);

🛡️ 防御方式:
  • 使用 commit-reveal 策略

    • 用户先提交加密数据(commit),后提交明文(reveal);

  • 延迟执行 + 随机性机制

    • 引入链上随机数,避免固定执行顺序;

  • Flashbots

    • 将交易发送至 Flashbots 私有池,避免泄露到公共 mempool;

  • 签名授权后端执行

    • 用户授权后由后端发送交易,缩短暴露时间窗口;


🎁 6.3 如果要做代币空投(Airdrop),你如何设计安全的分发策略?

✅ 目标:确保代币安全发放、避免滥领、节省 Gas。
📌 安全空投策略设计:
  1. Merkle Tree 空投(常用):

    • 构造用户地址+数量的 Merkle Root,存入合约;

    • 用户自行调用 claim() 提供 Merkle proof;

    • ✅ 优点:一次部署即可支持大规模空投,节省 Gas;

    • ✅ 防止重复领取,通过记录 claimed[address] = true

  2. 签名式空投

    • 后端为每个地址签名分发信息;

    • 用户提交签名至合约,合约验证签名;

    • 适合灵活分发、动态设置领取者;

  3. Batch Transfer + 权限限制

    • 批量发送空投(transferBatch());

    • 控制可操作账户,避免私钥被盗后滥发;

✅ 安全建议:
  • 空投逻辑使用开源库(如 OpenZeppelin MerkleDistributor)

  • 空投合约部署后不可修改 Merkle Root;

  • 添加空投截止时间、防多次领取、防重入等措施;


🔁 6.4 合约升级有几种方式?各自的优缺点?

✅ 1. 代理合约(Proxy Pattern):
  • 实现方式:使用 delegatecall 将调用转发至逻辑合约;

  • 典型模式

    • Transparent Proxy(OpenZeppelin)

    • UUPS Proxy(更轻量,推荐)

模式 优点 缺点
Transparent 稳定,OpenZeppelin支持 存储布局要求严格,结构复杂
UUPS 更节省 Gas,可自定义升级逻辑 升级函数自身易被攻击,需审慎授权

✅ 2. 数据迁移升级:
  • 新部署一个合约,人工迁移数据;

  • ✅ 优点:无 delegatecall 安全风险;

  • ❌ 缺点:迁移成本高、用户需重新授权;

✅ 3. Eternal Storage 模式:
  • 将状态变量独立放在一个固定合约;

  • 易维护,但结构复杂、不推荐新项目使用;


🧨 6.5 哪些 Solidity 编码模式容易出安全漏洞?

🚨 常见风险编码模式:
漏洞类型 示例代码 / 描述 防御方式
重入攻击 调用外部合约前修改状态(如提现) Checks-Effects-Interactions;使用 ReentrancyGuard
整数溢出/下溢 uint256 a = b - c(未判断 b > c) 使用 SafeMath 或启用 Solidity ≥0.8 自动检查
无访问控制 没有限制 setOwner() 添加 onlyOwnerAccessControl
调用未初始化合约地址 外部合约地址为空调用 require 地址非 0 且合约存在
delegatecall 滥用 调用非可信合约逻辑代码 限制 delegatecall 使用,仅可信模块
Gas limit 不足 数组遍历转账 gas 用尽,状态不变 加限制、使用 pull 模式而非 push
tx.origin 验证身份 require(tx.origin == owner) 易被 phishing msg.sender 替代 tx.origin


📌 总结建议:

  • 使用 OpenZeppelin 工具、Hardhat 插件审计合约;

  • 引入 CI 检查(如 slithermythx);

  • 所有用户交互都应防御重入、钓鱼、溢出权限越权

  • 升级合约需严格测试、控制 upgrade 权限;

  • 尽量使用 audited 合约库,避免“自己写轮子”;


网站公告

今日签到

点亮在社区的每一天
去签到