名称: multiversx-dapp-audit 描述: 审计前端dApp组件的安全漏洞,涉及钱包集成和交易处理。在审查使用sdk-dapp的React/TypeScript dApp或评估客户端安全时使用。
MultiversX dApp 审计员
审计使用@multiversx/sdk-dapp构建的MultiversX应用程序的前端组件。此技能专注于客户端安全、交易构造和钱包集成漏洞。
何时使用
- 审查React/TypeScript dApp代码
- 审计钱包连接实现
- 评估交易签名安全
- 检查XSS和数据暴露漏洞
- 验证前端-后端安全边界
1. 交易构造安全
威胁模型
前端构造用户签名的交易载荷。此处的漏洞可能诱骗用户签署恶意交易。
载荷操纵
// 易受攻击:用户输入直接用于交易数据
const sendTransaction = async (userInput: string) => {
const tx = new Transaction({
receiver: Address.newFromBech32(recipientAddress),
data: Buffer.from(userInput), // 攻击者控制数据!
// ...
});
await signAndSend(tx);
};
// 安全:验证和清理所有输入
const sendTransaction = async (functionName: string, args: string[]) => {
// 白名单允许的函数
const allowedFunctions = ['stake', 'unstake', 'claim'];
if (!allowedFunctions.includes(functionName)) {
throw new Error('无效函数');
}
// 验证参数
const sanitizedArgs = args.map(arg => validateArgument(arg));
const tx = new Transaction({
receiver: contractAddress,
data: Buffer.from(`${functionName}@${sanitizedArgs.join('@')}`),
// ...
});
await signAndSend(tx);
};
关键检查
| 检查 | 风险 | 缓解措施 |
|---|---|---|
| 接收地址验证 | 资金发送到错误地址 | 验证已知地址 |
| 数据载荷构造 | 恶意函数调用 | 白名单允许操作 |
| 金额验证 | 错误值转移 | 与用户确认金额 |
| 燃气限制操纵 | 交易失败 | 使用适当限制 |
2. 签名安全
盲签名风险
用户可能在不理解内容的情况下签署交易:
// 危险:签署不透明数据
const signMessage = async (data: string) => {
const hash = keccak256(data);
return await wallet.signMessage(hash); // 用户只看到哈希!
};
// 安全:向用户显示清晰消息
const signMessage = async (message: string) => {
// 在签名前向用户显示消息
const confirmed = await showConfirmationDialog({
title: '签署消息',
content: `您正在签署:"${message}"`,
warning: '仅签署您理解的消息'
});
if (!confirmed) throw new Error('用户拒绝');
return await wallet.signMessage(message);
};
交易预览要求
在签名前,用户应看到:
- 接收地址(如果已知则验证)
- 转移金额
- 代币类型(EGLD、ESDT、NFT)
- 调用函数(如果是智能合约交互)
- 燃气成本估计
3. 敏感数据处理
私钥安全
// 关键漏洞:切勿这样做
localStorage.setItem('privateKey', wallet.privateKey);
localStorage.setItem('mnemonic', wallet.mnemonic);
sessionStorage.setItem('seed', wallet.seed);
// 在代码审查中检查这些模式:
// - 任何私钥、助记词或种子的存储
// - 敏感数据日志记录
// - 向API发送敏感数据
安全模式
// 正确:使用sdk-dapp的安全会话管理
import { initApp } from '@multiversx/sdk-dapp/out/methods/initApp/initApp';
initApp({
storage: {
getStorageCallback: () => sessionStorage // 仅会话,非持久
},
dAppConfig: {
nativeAuth: {
expirySeconds: 3600 // 短生命周期令牌
}
}
});
访问令牌安全
// 易受攻击:令牌在URL中暴露
window.location.href = `https://api.example.com?accessToken=${token}`;
// 易受攻击:令牌在控制台
console.log('认证令牌:', accessToken);
// 安全:令牌在授权头中,从不记录
fetch(apiUrl, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
4. XSS预防
用户生成内容
// 易受攻击:直接HTML注入
const UserProfile = ({ bio }: { bio: string }) => {
return <div dangerouslySetInnerHTML={{ __html: bio }} />; // XSS!
};
// 安全:React的默认转义
const UserProfile = ({ bio }: { bio: string }) => {
return <div>{bio}</div>; // 自动转义
};
// 如果必须使用HTML,先清理
import DOMPurify from 'dompurify';
const UserProfile = ({ bio }: { bio: string }) => {
const sanitized = DOMPurify.sanitize(bio);
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
};
URL处理
// 易受攻击:未验证重定向
const handleCallback = () => {
const returnUrl = new URLSearchParams(window.location.search).get('returnUrl');
window.location.href = returnUrl!; // 开放重定向!
};
// 安全:验证重定向URL
const handleCallback = () => {
const returnUrl = new URLSearchParams(window.location.search).get('returnUrl');
const allowed = ['/', '/dashboard', '/profile'];
if (allowed.includes(returnUrl || '')) {
window.location.href = returnUrl!;
} else {
window.location.href = '/'; // 默认安全重定向
}
};
5. API通信安全
HTTPS强制
// 易受攻击:HTTP连接
const API_URL = 'http://api.example.com'; // 不安全!
// 安全:始终HTTPS
const API_URL = 'https://api.example.com';
// 在代码中验证:所有API URL必须使用https://
请求/响应验证
// 易受攻击:盲目信任API响应
const balance = await fetch('/api/balance').then(r => r.json());
displayBalance(balance.amount); // 如果API被攻击怎么办?
// 安全:验证响应结构
const response = await fetch('/api/balance').then(r => r.json());
if (typeof response.amount !== 'string' || !/^\d+$/.test(response.amount)) {
throw new Error('无效余额响应');
}
displayBalance(response.amount);
6. 审计工具和技术
网络流量分析
# 使用浏览器DevTools网络标签检查:
# - 所有API请求和响应
# - 发送的交易数据
# - 头信息(尤其是授权)
# - WebSocket消息
# 或使用代理工具:
# - Burp Suite
# - mitmproxy
# - Charles Proxy
代码审查模式
# 搜索危险模式
grep -r "localStorage" src/
grep -r "dangerouslySetInnerHTML" src/
grep -r "eval(" src/
grep -r "privateKey\|mnemonic\|seed" src/
grep -r "console.log" src/ # 检查敏感数据日志
浏览器安全头检查
内容安全策略: default-src 'self'; script-src 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
7. 认证流程审计
钱包连接
// 验证钱包连接流程:
// 1. 用户发起连接
// 2. 钱包提供商提示批准
// 3. 仅共享公钥地址给dApp
// 4. 无私有数据传输
// 检查UnlockPanelManager使用
const unlockPanelManager = UnlockPanelManager.init({
loginHandler: () => {
// 验证:此处无敏感数据处理
navigate('/dashboard');
}
});
会话管理
// 验证会话安全:
// - 令牌过期强制执行
// - 注销清除所有会话数据
// - 无持久敏感存储
const handleLogout = async () => {
const provider = getAccountProvider();
await provider.logout();
// 验证:会话存储已清除
sessionStorage.clear();
navigate('/');
};
8. 审计清单
交易安全
- [ ] 所有交易数据在签名前已验证
- [ ] 向用户显示清晰交易预览
- [ ] 接收地址已验证
- [ ] 大额转移的金额确认
- [ ] 燃气限制适合操作
数据安全
- [ ] 无任何存储中的私钥
- [ ] 无控制台日志中的敏感数据
- [ ] 访问令牌未在URL中暴露
- [ ] 所有API调用强制HTTPS
XSS预防
- [ ] 无与用户输入的
dangerouslySetInnerHTML - [ ] 无与用户输入的
eval() - [ ] URL重定向已验证
- [ ] 内容安全策略头存在
会话安全
- [ ] 令牌过期强制执行
- [ ] 注销清除所有会话数据
- [ ] 保护路由正确守卫
- [ ] 敏感操作的重新认证
9. 报告模板
# dApp安全审计报告
## 范围
- 应用:[名称]
- 版本:[版本]
- 审查文件:[数量]
## 发现
### 关键
| ID | 描述 | 位置 | 建议 |
|----|-------------|----------|----------------|
| C1 | ... | ... | ... |
### 高
...
### 中
...
### 信息性
...
## 建议总结
1. [优先建议]
2. ...
## 结论
[整体评估]