安全最佳实践
这是一篇面向 Soroban Registry API 和智能合约开发的安全最佳实践文档,系统介绍了认证授权、API 安全、合约审计、密钥管理、输入校验、加密与安全头等关键措施。内容覆盖了从开发、部署到运维的完整安全流程,并给出多语言示例代码和部署前检查清单。
安全最佳实践
概述
本文档涵盖了使用 Soroban Registry API、部署智能合约以及处理敏感数据的安全最佳实践。遵循这些指南有助于保护你的应用程序、用户以及更广泛的 Stellar 生态系统。
目录
认证与授权
当前认证模型
目前,Soroban Registry API 对读取操作是公开可访问的,无需认证。未来版本将实现 API key 认证。
计划中的认证(即将推出)
API Key 认证:
GET /api/contracts/{id}
Authorization: Bearer your-api-key-here
最佳实践:
- 将 API keys 存储在环境变量中,绝不要写入代码
- 每 90 天轮换一次 keys
- 开发和生产环境使用不同的 keys
- 立即吊销已泄露的 keys
- 绝不要在公共仓库或日志中共享 keys
授权模型
该 registry 实现基于角色的访问控制(RBAC):
| Role | Permissions |
|---|---|
| Anonymous | 读取公开合约、搜索、查看已验证源码 |
| Registered User | 发布合约、验证合约、管理自己的合约 |
| Publisher | 以已验证身份发布、管理 publisher profile |
| Admin | 管理所有合约、用户、审核内容 |
最小权限原则:始终只使用你的用例所需的最小权限。
API 安全
安全使用 API
1. 始终使用 HTTPS
在生产环境中,绝不要通过 HTTP 发送请求:
// ✅ 正确
const API_URL = 'https://registry.soroban.example';
// ❌ 错误
const API_URL = 'http://registry.soroban.example';
2. 验证 TLS Certificates
确保你的 HTTP client 会验证 TLS certificates:
import requests
## ✅ 正确(默认)
response = requests.get(url, verify=True)
## ❌ 错误 - 禁用证书验证
response = requests.get(url, verify=False)
3. 设置请求超时
始终设置超时以防止请求挂起:
import requests
response = requests.get(
url,
timeout=30 # 30 秒超时
)
const response = await fetch(url, {
signal: AbortSignal.timeout(30000) // 30 秒超时
});
4. 清理用户输入
绝不要将用户输入直接插入 API 请求中:
## ❌ 错误 - 易受注入攻击
contract_id = user_input
url = f"https://api.example/contracts/{contract_id}"
## ✅ 正确 - 先验证
import re
if re.match(r'^C[A-Z0-9]{55}$', user_input):
contract_id = user_input
url = f"https://api.example/contracts/{contract_id}"
else:
raise ValueError("Invalid contract ID")
5. 安全地处理错误
不要在错误消息中暴露敏感信息:
## ❌ 错误 - 暴露敏感数据
except Exception as e:
return f"Error: {e}, API_KEY: {API_KEY}, DB_CONN: {DB_CONN}"
## ✅ 正确 - 清理错误消息
except Exception as e:
logger.error(f"API error: {e}", extra={"correlation_id": correlation_id})
return {"error": "An error occurred. Please try again.", "correlation_id": correlation_id}
智能合约安全
发布合约之前
1. 代码审查
- 让安全专家审查合约
- 使用自动化工具(soroban-lint)
- 遵循 Stellar 智能合约最佳实践
2. 审计常见漏洞
在发布之抢跑 soroban-lint:
soroban-lint scan src/ --all-rules
需要检查的常见漏洞:
| Vulnerability | Risk | Prevention |
|---|---|---|
| 缺少 auth 检查 | 未经授权访问 | 使用 env.current_contract_address() 检查 |
| 整数溢出 | 计算错误 | 使用 checked arithmetic |
| Reentrancy | 状态损坏 | 使用 checks-effects-interactions 模式 |
| 无界循环 | 通过 gas 耗尽导致 DoS | 设置最大迭代限制 |
| Unsafe unwrap | panic/合约停止 | 使用 ? 操作符或适当的错误处理 |
3. 充分测试
## 运行所有测试
cargo test
## 使用 fuzzing 测试
cargo fuzz
## 在 testnet 上进行集成测试
soroban contract invoke --id $CONTRACT --network testnet
4. 验证合约源码
部署后始终验证你的合约:
soroban-registry verify \
--contract-id $CONTRACT_ID \
--source ./src \
--network mainnet
为什么? 验证可以向用户证明已部署的 bytecode 与公开源代码一致。
不要在合约中包含 Secrets
// ❌ 错误 - 硬编码 secrets
const ADMIN_KEY: &str = "SDFY3LK...PRIVATE_KEY";
// ✅ 正确 - 作为参数传入
pub fn admin_action(env: Env, admin: Address) {
admin.require_auth();
// ...
}
合约中的输入验证
pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
// ✅ 验证输入
if amount <= 0 {
panic!("Amount must be positive");
}
if from == to {
panic!("Cannot transfer to self");
}
// 执行转账
}
数据保护
个人数据处理
如果你的应用通过 registry 收集个人数据:
- 最小化数据收集 - 只收集必要内容
- 加密敏感数据,包括静态存储和传输中
- 实施数据保留策略 - 删除旧数据
- 提供数据导出/删除 - 用户权利(GDPR)
- 记录对个人数据的访问 - 审计轨迹
数据分类
| Classification | Examples | Protection Required |
|---|---|---|
| Public | 合约地址、已验证源码 | 无 |
| Internal | API metrics、usage statistics | 访问控制 |
| Confidential | 用户 emails、API keys | 加密 + 访问控制 |
| Secret | 私钥、数据库密码 | HSM/vault + 严格访问 |
Secrets 管理
永远不要将 Secrets 提交到 Git
## 添加到 .gitignore
.env
.env.local
*.key
*.pem
secrets/
使用环境变量
## .env(绝不要提交这个文件)
DATABASE_URL=postgresql://user:password@localhost/db
API_KEY=your-api-key-here
STELLAR_SECRET_KEY=SDFY3LK...
import os
from dotenv import load_dotenv
load_dotenv()
DATABASE_URL = os.getenv('DATABASE_URL')
API_KEY = os.getenv('API_KEY')
使用 Secret 管理工具
用于生产环境:
- AWS Secrets Manager - 用于 AWS 部署
- HashiCorp Vault - 用于自托管
- Azure Key Vault - 用于 Azure 部署
- Google Secret Manager - 用于 GCP 部署
HashiCorp Vault 示例:
import hvac
client = hvac.Client(url='https://vault.example.com')
client.token = os.getenv('VAULT_TOKEN')
secret = client.secrets.kv.v2.read_secret_version(path='soroban/api-key')
API_KEY = secret['data']['data']['key']
定期轮换 Secrets
- API Keys:每 90 天
- 数据库密码:每 180 天
- TLS Certificates:在过期前(通常 90 天)
- Signing Keys:每 365 天
输入验证
验证所有用户输入
永远不要信任用户输入。始终在服务器端进行验证。
Contract ID 验证
import re
def validate_contract_id(contract_id: str) -> bool:
"""
Stellar contract IDs 是 56 个字符,以 'C' 开头
"""
pattern = r'^C[A-Z2-7]{55}$'
return bool(re.match(pattern, contract_id))
## 用法
if not validate_contract_id(user_input):
raise ValueError("Invalid contract ID format")
Network 验证
VALID_NETWORKS = {'mainnet', 'testnet', 'futurenet'}
def validate_network(network: str) -> bool:
return network.lower() in VALID_NETWORKS
分页验证
def validate_pagination(limit: int, offset: int):
if not (1 <= limit <= 1000):
raise ValueError("Limit must be between 1 and 1000")
if offset < 0:
raise ValueError("Offset must be non-negative")
防止 XSS(Cross-Site Scripting)
当显示用户生成内容(合约名称、描述)时:
// ✅ React 会自动转义
function ContractCard({ name, description }) {
return (
<div>
<h2>{name}</h2> {/* 自动转义 */}
<p>{description}</p>
</div>
);
}
// ❌ 危险 - 可能注入 scripts
function ContractCard({ name, description }) {
return (
<div dangerouslySetInnerHTML={{ __html: description }} />
);
}
用于 HTML sanitization:
import DOMPurify from 'dompurify';
const cleanHtml = DOMPurify.sanitize(userInput);
防止 SQL Injection
始终使用参数化查询:
## ❌ 错误 - 易受 SQL injection 攻击
query = f"SELECT * FROM contracts WHERE id = '{contract_id}'"
result = db.execute(query)
## ✅ 正确 - 参数化查询
query = "SELECT * FROM contracts WHERE id = $1"
result = await db.fetch_one(query, contract_id)
// ✅ 使用 sqlx 正确写法
let contract = sqlx::query_as::<_, Contract>(
"SELECT * FROM contracts WHERE contract_id = $1"
)
.bind(contract_id)
.fetch_one(&pool)
.await?;
速率限制与 DDoS 防护
遵守速率限制
详情请参见 API Rate Limiting。
要点:
- 监控
X-RateLimit-RemainingHeader - 对 429 errors 实现指数退避
- 尽可能缓存响应
- 对批量操作使用 batch endpoints
实现客户端速率限制
class RateLimiter {
constructor(maxRequests, perMilliseconds) {
this.max = maxRequests;
this.window = perMilliseconds;
this.requests = [];
}
async acquire() {
const now = Date.now();
this.requests = this.requests.filter(t => t > now - this.window);
if (this.requests.length >= this.max) {
const oldestRequest = this.requests[0];
const waitTime = oldestRequest + this.window - now;
await new Promise(resolve => setTimeout(resolve, waitTime));
return this.acquire();
}
this.requests.push(now);
}
}
// 用法:每分钟 100 次请求
const limiter = new RateLimiter(100, 60000);
async function apiCall(url) {
await limiter.acquire();
return fetch(url);
}
安全 Headers
CORS 配置
正确配置 CORS 以防止未经授权的跨域请求:
// 后端 CORS 配置
use tower_http::cors::{CorsLayer, Any};
let cors = CorsLayer::new()
.allow_origin("https://app.example.com".parse::<HeaderValue>().unwrap())
.allow_methods([Method::GET, Method::POST])
.allow_headers([AUTHORIZATION, CONTENT_TYPE]);
生产环境:白名单指定 origins
开发环境:可以使用 allow_origin(Any),但绝不要用于生产环境
Content Security Policy (CSP)
向前端添加 CSP headers:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://registry.soroban.example;">
其他安全 Headers
## 防止 clickjacking
X-Frame-Options: DENY
## 防止 MIME sniffing
X-Content-Type-Options: nosniff
## 启用 XSS protection
X-XSS-Protection: 1; mode=block
## 强制 HTTPS
Strict-Transport-Security: max-age=31536000; includeSubDomains
## Referrer policy
Referrer-Policy: strict-origin-when-cross-origin
加密
静态数据
数据库加密:
- 使用加密存储卷(如 AWS EBS encryption 等)
- 启用数据库级加密(PostgreSQL pgcrypto)
- 单独加密敏感列
示例:在数据库中加密 API keys
from cryptography.fernet import Fernet
## 生成 key(安全存储,不要写在代码中!)
ENCRYPTION_KEY = os.getenv('ENCRYPTION_KEY')
cipher = Fernet(ENCRYPTION_KEY)
def encrypt_api_key(api_key: str) -> bytes:
return cipher.encrypt(api_key.encode())
def decrypt_api_key(encrypted_key: bytes) -> str:
return cipher.decrypt(encrypted_key).decode()
传输中的数据
始终使用 TLS 1.2 或更高版本:
## Nginx TLS 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
证书管理:
- 使用 Let's Encrypt 获取免费的 TLS certificates
- 设置自动续期
- 监控证书过期时间
部署前安全检查清单
在部署到生产环境之前使用此检查清单:
应用安全
- 所有 secrets 都在环境变量中(不是硬编码)
-
.env和.env.local已加入.gitignore - 日志中没有敏感数据
- 所有用户输入都已验证
- 已防止 SQL injection(参数化查询)
- 已实现 XSS 防护
- 已启用 CSRF 防护
- 已配置速率限制
- 已设置安全 Headers(CSP、X-Frame-Options 等)
- CORS 配置正确
- 错误消息不会暴露敏感信息
基础设施安全
- 已强制 TLS/HTTPS
- TLS certificates 有效且不会很快过期
- 数据库访问已受限制(防火墙规则)
- 未使用默认密码
- 服务器访问使用 SSH keys(不是密码)
- 防火墙已配置(仅开放必要端口)
- 已启用安全事件日志记录
- 已配置自动备份
- 已记录灾难恢复计划
智能合约安全
- 合约代码已由安全专家审查
- soroban-lint 通过且无严重问题
- 所有测试均通过
- 已完成 testnet 上的集成测试
- 合约部署后已在 registry 中验证
- 合约中没有硬编码 secrets
- 已实现授权检查
- 已防止整数溢出
- 已考虑 Gas 限制(避免无界循环)
监控与事件响应
- 已启用安全监控(登录失败、异常活动)
- 已为安全事件配置告警
- 已记录事件响应计划
- 安全联系方式公开(SECURITY.md)
- 已定义漏洞披露流程
- 日志已保留用于审计(30-90 天)
合规与文档
- 隐私政策已发布(如果收集个人数据)
- 服务条款已发布
- 安全文档已更新
- 已扫描依赖漏洞(
cargo audit、npm audit) - 已审查第三方服务安全性
代码审查安全指南
审查代码时,请检查:
认证与授权
- 所有受保护端点都进行了 auth 检查
- 用户只能访问自己的资源
- 管理操作需要 admin role
- JWT tokens 已正确验证
输入验证
- 所有用户输入都已验证
- 已进行类型检查
- 已强制范围限制
- 没有 SQL injection 向量
- 没有命令注入向量
错误处理
- 错误不会暴露敏感数据
- 生产环境不会返回 stack traces
- 使用 correlation IDs 进行调试
- 错误已安全记录
密码学
- 没有自定义 crypto(使用经过审查的库)
- 使用强算法(AES-256、RSA-2048+)
- 随机数生成在密码学上是安全的
- keys 没有硬编码
依赖项
- 依赖项中没有已知漏洞
- 依赖项来自可信来源
- 依赖树尽可能精简(移除未使用项)
- 依赖版本已固定
依赖扫描
定期扫描漏洞:
Rust
## 安装 cargo-audit
cargo install cargo-audit
## 扫描漏洞
cargo audit
## 自动修复(如果可用)
cargo audit fix
JavaScript/Node.js
## 扫描
npm audit
## 自动修复
npm audit fix
## 仅针对生产依赖
npm audit --production
Python
## 安装 safety
pip install safety
## 扫描
safety check
## 检查特定文件
safety check -r requirements.txt
安全更新
保持所有软件为最新:
## Rust toolchain
rustup update
## Soroban CLI
cargo install soroban-cli --force
## 依赖
cargo update
npm update
自动化更新:
- 使用 Dependabot(GitHub)自动更新依赖
- 在合并前审查并测试更新
- 订阅 Stellar/Soroban 的安全邮件列表
报告安全问题
如果你发现了安全漏洞:
- 不要公开创建 GitHub issue
- 按照 Security Policy 进行负责任披露
- 邮箱:security@soroban-registry.example
- 提供详细的复现步骤
相关文档
- Root Security Policy - 漏洞报告
- API Rate Limiting - 速率限制配置
- Error Codes - 错误处理
- Verification Workflow - 合约验证
安全资源
Stellar/Soroban 安全
通用安全
工具
- soroban-lint - Soroban 安全 lint 工具
- cargo-audit - Rust 依赖扫描器
- npm audit - Node.js 依赖扫描器
最后更新: 2026-02-24
保持安全!?
- 原文链接: github.com/ALIPHATICHYD/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~