Web3安全审查
aibot882026-10-28查看 1579复制 1143
Web3 和区块链应用的安全模式——Solana 钱包签名验证、交易验证、智能合约交互安全,以及 DeFi/NFT 功能检查清单。
📘如何使用这个技能
- 1复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
- 2打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
- 3粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
- 4直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景
💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。
SKILL.md4586 chars
---
name: security-review-web3
description: Security patterns for Web3 and blockchain applications — Solana wallet signature verification, transaction validation, smart contract interaction security, and checklist for DeFi/NFT features.
---
# Security Review — Web3 & Blockchain
Security patterns for applications that interact with blockchains, wallets, and smart contracts.
## When to Activate
- Implementing wallet-based authentication (Solana, Ethereum, EVM chains)
- Verifying on-chain transaction signatures before processing user actions
- Building smart contract interaction logic (minting, trading, staking)
- Implementing DeFi features with balance checks and transaction limits
- Auditing Web3-specific attack surfaces (replay attacks, reentrancy via callbacks)
> For general security (injection, auth, secrets, OWASP Top 10) — see skill `security-review`.
> For auth patterns (JWT, OAuth, sessions) — see skill `auth-patterns`.
## Solana Wallet Verification
### Wallet Signature Verification
```typescript
import { verify } from '@solana/web3.js'
async function verifyWalletOwnership(
publicKey: string,
signature: string,
message: string
) {
try {
const isValid = verify(
Buffer.from(message),
Buffer.from(signature, 'base64'),
Buffer.from(publicKey, 'base64')
)
return isValid
} catch (error) {
return false
}
}
```
### Transaction Verification
```typescript
async function verifyTransaction(transaction: Transaction) {
// Verify recipient
if (transaction.to !== expectedRecipient) {
throw new Error('Invalid recipient')
}
// Verify amount
if (transaction.amount > maxAmount) {
throw new Error('Amount exceeds limit')
}
// Verify user has sufficient balance
const balance = await getBalance(transaction.from)
if (balance < transaction.amount) {
throw new Error('Insufficient balance')
}
return true
}
```
## Security Checklist (Web3)
- [ ] Wallet signatures verified server-side before trusting identity
- [ ] Transaction details validated (recipient, amount, token)
- [ ] Balance checks performed before executing transactions
- [ ] No blind transaction signing — always validate content before submitting
- [ ] Replay attack protection (nonce or timestamp in signed message)
- [ ] Smart contract addresses pinned — never accept user-supplied contract addresses
- [ ] Amount limits enforced server-side (not just client-side)
- [ ] Rate limiting on transaction submission endpoints
## Common Web3 Attack Vectors
| Attack | Description | Fix |
|--------|-------------|-----|
| Replay attack | Reusing a valid signed message | Include nonce + expiry in signed payload |
| Spoofed recipient | User-supplied destination address | Pin recipient addresses server-side |
| Amount overflow | Integer overflow in token math | Use `BN.js` or `BigInt` for all amounts |
| Reentrancy (EVM) | Callback executes before state update | Update state before external calls |
| Front-running | Transaction ordering manipulation | Use commit-reveal schemes |
## Reentrancy: Vulnerable vs. Safe Pattern
### Vulnerable (Classic Reentrancy)
```solidity
contract VulnerableVault {
mapping(address => uint256) public balances;
function withdraw(uint256 amount) external {
require(balances[msg.sender] >= amount, "Insufficient");
// ❌ External call BEFORE state update — attacker can re-enter here
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
balances[msg.sender] -= amount; // State updated AFTER call
}
}
```
**Attack vector:** Malicious contract's `receive()` calls `withdraw()` again before `balances` is decremented. Attacker can drain the vault.
### Safe (Checks-Effects-Interactions)
```solidity
contract SafeVault {
mapping(address => uint256) public balances;
function withdraw(uint256 amount) external {
// ✅ 1. Checks
require(balances[msg.sender] >= amount, "Insufficient");
// ✅ 2. Effects (state update BEFORE external call)
balances[msg.sender] -= amount;
// ✅ 3. Interactions (external call LAST)
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
```
**Rule:** Always follow Checks → Effects → Interactions order. For complex cases, add `ReentrancyGuard` from OpenZeppelin:
```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SafeVault is ReentrancyGuard {
function withdraw(uint256 amount) external nonReentrant { ... }
}
```