安全最佳实践

这是一篇面向 Soroban Registry API 和智能合约开发的安全最佳实践文档,系统介绍了认证授权、API 安全、合约审计、密钥管理、输入校验、加密与安全头等关键措施。内容覆盖了从开发、部署到运维的完整安全流程,并给出多语言示例代码和部署前检查清单。

安全最佳实践

概述

本文档涵盖了使用 Soroban Registry API、部署智能合约以及处理敏感数据的安全最佳实践。遵循这些指南有助于保护你的应用程序、用户以及更广泛的 Stellar 生态系统。

目录

  1. 认证与授权
  2. API 安全
  3. 智能合约安全
  4. 数据保护
  5. Secrets 管理
  6. 输入验证
  7. 速率限制与 DDoS 防护
  8. 安全 Headers
  9. 加密
  10. 部署前安全检查清单

认证与授权

当前认证模型

目前,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 收集个人数据:

  1. 最小化数据收集 - 只收集必要内容
  2. 加密敏感数据,包括静态存储和传输中
  3. 实施数据保留策略 - 删除旧数据
  4. 提供数据导出/删除 - 用户权利(GDPR)
  5. 记录对个人数据的访问 - 审计轨迹

数据分类

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-Remaining Header
  • 对 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 auditnpm 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 的安全邮件列表

报告安全问题

如果你发现了安全漏洞:

  1. 不要公开创建 GitHub issue
  2. 按照 Security Policy 进行负责任披露
  3. 邮箱:security@soroban-registry.example
  4. 提供详细的复现步骤

相关文档


安全资源

Stellar/Soroban 安全

通用安全

工具


最后更新: 2026-02-24

保持安全!🔒

  • 原文链接: github.com/ALIPHATICHYD/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ALIPHATICHYD
ALIPHATICHYD
江湖只有他的大名,没有他的介绍。