HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 交易所技术完整体系

    • 交易所技术完整体系
    • 交易所技术架构总览
    • 交易基础概念
    • 撮合引擎原理
    • 撮合引擎实现-内存撮合
    • 撮合引擎优化 - 延迟与吞吐
    • 撮合引擎高可用
    • 清算系统设计
    • 风控系统设计
    • 资金管理系统
    • 行情系统设计
    • 去中心化交易所(DEX)设计
    • 合约交易系统
    • 数据库设计与优化
    • 缓存与消息队列
    • 用户系统与KYC
    • 交易所API设计
    • 监控与告警系统
    • 安全防护与攻防
    • 高可用架构设计
    • 压力测试与性能优化
    • 项目实战-完整交易所实现

安全防护与攻防

1. 网络层防护

1.1 DDoS防护

防护策略:

┌──────────────────────────────────────────────────────────┐
│                      CDN (Cloudflare)                     │
│  全球分布式节点、自动DDoS清洗、防CC攻击                    │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────┴─────────────────────────────────────┐
│                   DDoS清洗中心                            │
│  流量分析、黑洞路由、限速                                  │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────┴─────────────────────────────────────┐
│                    WAF防火墙                              │
│  SQL注入防护、XSS防护、恶意Bot识别                         │
└────────────────────┬─────────────────────────────────────┘
                     │
┌────────────────────┴─────────────────────────────────────┐
│                   负载均衡器                              │
│  健康检查、限流、故障转移                                  │
└─────────────────────────────────────────────────────────┘

SYN Flood防护(TCP半连接攻击):

# Linux内核参数调优
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sysctl -w net.ipv4.tcp_synack_retries=2

# iptables限制每个IP的连接速率
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 60 --hitcount 20 -j DROP

HTTP Flood防护:

package middleware

import (
    "net/http"
    "sync"
    "time"
)

// 简单的IP限流
type IPRateLimiter struct {
    visitors map[string]*Visitor
    mu       sync.RWMutex
    rate     int
    burst    int
}

type Visitor struct {
    limiter  *rate.Limiter
    lastSeen time.Time
}

func NewIPRateLimiter(r, b int) *IPRateLimiter {
    limiter := &IPRateLimiter{
        visitors: make(map[string]*Visitor),
        rate:     r,
        burst:    b,
    }

    // 定期清理过期访客
    go limiter.cleanupVisitors()

    return limiter
}

func (rl *IPRateLimiter) getVisitor(ip string) *rate.Limiter {
    rl.mu.Lock()
    defer rl.mu.Unlock()

    visitor, exists := rl.visitors[ip]
    if !exists {
        limiter := rate.NewLimiter(rate.Limit(rl.rate), rl.burst)
        rl.visitors[ip] = &Visitor{limiter, time.Now()}
        return limiter
    }

    visitor.lastSeen = time.Now()
    return visitor.limiter
}

func (rl *IPRateLimiter) Limit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip := getClientIP(r)
        limiter := rl.getVisitor(ip)

        if !limiter.Allow() {
            http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
            return
        }

        next.ServeHTTP(w, r)
    })
}

func (rl *IPRateLimiter) cleanupVisitors() {
    for {
        time.Sleep(1 * time.Minute)

        rl.mu.Lock()
        for ip, visitor := range rl.visitors {
            if time.Since(visitor.lastSeen) > 3*time.Minute {
                delete(rl.visitors, ip)
            }
        }
        rl.mu.Unlock()
    }
}

func getClientIP(r *http.Request) string {
    // 优先获取X-Forwarded-For
    ip := r.Header.Get("X-Forwarded-For")
    if ip != "" {
        return strings.Split(ip, ",")[0]
    }

    // X-Real-IP
    ip = r.Header.Get("X-Real-IP")
    if ip != "" {
        return ip
    }

    // RemoteAddr
    return strings.Split(r.RemoteAddr, ":")[0]
}

1.2 WAF规则

# Nginx + ModSecurity WAF配置

# SQL注入防护
SecRule ARGS "@detectSQLi" \
    "id:1001,phase:2,deny,status:403,msg:'SQL Injection Detected'"

# XSS防护
SecRule ARGS "@detectXSS" \
    "id:1002,phase:2,deny,status:403,msg:'XSS Attack Detected'"

# 路径遍历防护
SecRule REQUEST_URI "@pmf ../../../" \
    "id:1003,phase:1,deny,status:403,msg:'Path Traversal Attack'"

# 禁止常见扫描器
SecRule HTTP_USER_AGENT "@pmf sqlmap nikto nmap masscan" \
    "id:1004,phase:1,deny,status:403,msg:'Scanner Detected'"

# 限制请求体大小
SecRequestBodyLimit 1048576  # 1MB

# 限制文件上传大小
SecRequestBodyLimitAction ProcessPartial

2. 应用层防护

2.1 SQL注入防护

错误示例(拼接SQL):

//  危险:SQL注入漏洞
func GetUserByEmail(email string) (*User, error) {
    query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email)
    // 如果email = "' OR '1'='1"
    // 查询变成:SELECT * FROM users WHERE email = '' OR '1'='1'
    // 返回所有用户!
}

正确做法(参数化查询):

//  安全:使用参数化查询
func GetUserByEmail(email string) (*User, error) {
    var user User
    err := db.QueryRow("SELECT * FROM users WHERE email = ?", email).Scan(
        &user.ID, &user.Email, &user.PasswordHash,
    )
    return &user, err
}

ORM防护(使用GORM):

import "gorm.io/gorm"

func GetUserByEmail(db *gorm.DB, email string) (*User, error) {
    var user User
    // GORM自动参数化
    err := db.Where("email = ?", email).First(&user).Error
    return &user, err
}

2.2 XSS防护

输出转义:

import "html/template"

func RenderUserProfile(w http.ResponseWriter, user *User) {
    tmpl := template.Must(template.New("profile").Parse(`
        <div>
            <h1>{{.Name}}</h1>
            <p>{{.Bio}}</p>
        </div>
    `))

    // template包会自动HTML转义
    tmpl.Execute(w, user)
}

// 如果user.Bio = "<script>alert('XSS')</script>"
// 输出:&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;

CSP (Content Security Policy):

func SetSecurityHeaders(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // CSP:只允许同源脚本
        w.Header().Set("Content-Security-Policy",
            "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'")

        // XSS保护
        w.Header().Set("X-XSS-Protection", "1; mode=block")

        // 防止MIME类型嗅探
        w.Header().Set("X-Content-Type-Options", "nosniff")

        // 防止点击劫持
        w.Header().Set("X-Frame-Options", "DENY")

        // HSTS:强制HTTPS
        w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")

        next.ServeHTTP(w, r)
    })
}

2.3 CSRF防护

package csrf

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "errors"
    "fmt"
    "net/http"
    "strings"
    "time"
)

type CSRFProtection struct {
    secret []byte
}

func NewCSRFProtection(secret string) *CSRFProtection {
    return &CSRFProtection{
        secret: []byte(secret),
    }
}

// 生成CSRF Token
func (cp *CSRFProtection) GenerateToken(sessionID string) string {
    // token = base64(sessionID:timestamp:signature)
    timestamp := time.Now().Unix()
    message := fmt.Sprintf("%s:%d", sessionID, timestamp)

    h := hmac.New(sha256.New, cp.secret)
    h.Write([]byte(message))
    signature := base64.StdEncoding.EncodeToString(h.Sum(nil))

    token := fmt.Sprintf("%s:%s", message, signature)
    return base64.StdEncoding.EncodeToString([]byte(token))
}

// 验证CSRF Token
func (cp *CSRFProtection) ValidateToken(token, sessionID string) error {
    // 解码token
    decoded, err := base64.StdEncoding.DecodeString(token)
    if err != nil {
        return errors.New("invalid token format")
    }

    parts := strings.Split(string(decoded), ":")
    if len(parts) != 3 {
        return errors.New("invalid token structure")
    }

    tokenSessionID := parts[0]
    timestamp := parts[1]
    signature := parts[2]

    // 验证session ID
    if tokenSessionID != sessionID {
        return errors.New("session mismatch")
    }

    // 验证签名
    message := fmt.Sprintf("%s:%s", tokenSessionID, timestamp)
    h := hmac.New(sha256.New, cp.secret)
    h.Write([]byte(message))
    expectedSig := base64.StdEncoding.EncodeToString(h.Sum(nil))

    if signature != expectedSig {
        return errors.New("invalid signature")
    }

    // 验证时间戳(1小时内有效)
    var ts int64
    fmt.Sscanf(timestamp, "%d", &ts)
    if time.Now().Unix()-ts > 3600 {
        return errors.New("token expired")
    }

    return nil
}

// 中间件
func (cp *CSRFProtection) Protect(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // GET请求不需要CSRF保护
        if r.Method == "GET" || r.Method == "HEAD" || r.Method == "OPTIONS" {
            next.ServeHTTP(w, r)
            return
        }

        // 获取session ID
        sessionID := getSessionID(r)

        // 从Header或Form中获取CSRF Token
        token := r.Header.Get("X-CSRF-Token")
        if token == "" {
            token = r.FormValue("csrf_token")
        }

        // 验证token
        err := cp.ValidateToken(token, sessionID)
        if err != nil {
            http.Error(w, "CSRF validation failed", http.StatusForbidden)
            return
        }

        next.ServeHTTP(w, r)
    })
}

3. 业务层防护

3.1 订单重放攻击防护

type OrderService struct {
    redis *redis.Client
}

func (os *OrderService) PlaceOrder(order *Order) error {
    // 1. 生成唯一的请求ID(客户端提供)
    requestID := order.RequestID
    if requestID == "" {
        return errors.New("request_id required")
    }

    // 2. 检查是否已处理(防重放)
    key := fmt.Sprintf("order:request:%s", requestID)
    exists, err := os.redis.SetNX(context.Background(), key, "1", 5*time.Minute).Result()

    if !exists {
        return errors.New("duplicate request")
    }

    // 3. 处理订单
    err = os.processOrder(order)
    if err != nil {
        // 失败时删除redis key,允许重试
        os.redis.Del(context.Background(), key)
        return err
    }

    return nil
}

3.2 价格操纵检测

type PriceManipulationDetector struct {
    db *sql.DB
}

// 检测异常订单
func (pmd *PriceManipulationDetector) CheckOrder(order *Order) error {
    // 1. 获取当前市场价
    marketPrice, err := pmd.getMarketPrice(order.Symbol)
    if err != nil {
        return err
    }

    // 2. 价格偏离检测
    deviation := abs(order.Price-marketPrice) / marketPrice

    if deviation > 0.1 { // 偏离10%
        return fmt.Errorf("price deviation too large: %.2f%%", deviation*100)
    }

    // 3. 自成交检测
    err = pmd.checkSelfTrading(order)
    if err != nil {
        return err
    }

    // 4. 洗盘交易检测
    err = pmd.checkWashTrading(order)
    if err != nil {
        return err
    }

    return nil
}

// 自成交检测
func (pmd *PriceManipulationDetector) checkSelfTrading(order *Order) error {
    // 查询订单簿中是否有同一用户的反向订单
    var count int
    err := pmd.db.QueryRow(`
        SELECT COUNT(*) FROM orders
        WHERE user_id = ?
          AND symbol = ?
          AND side != ?
          AND status = 'pending'
    `, order.UserID, order.Symbol, order.Side).Scan(&count)

    if err != nil {
        return err
    }

    if count > 0 {
        return errors.New("potential self-trading detected")
    }

    return nil
}

// 洗盘交易检测
func (pmd *PriceManipulationDetector) checkWashTrading(order *Order) error {
    // 检查用户最近是否频繁买卖同一交易对
    var buyCount, sellCount int
    err := pmd.db.QueryRow(`
        SELECT
            SUM(CASE WHEN side = 'buy' THEN 1 ELSE 0 END) as buy_count,
            SUM(CASE WHEN side = 'sell' THEN 1 ELSE 0 END) as sell_count
        FROM orders
        WHERE user_id = ?
          AND symbol = ?
          AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)
    `, order.UserID, order.Symbol).Scan(&buyCount, &sellCount)

    if err != nil {
        return err
    }

    // 如果买卖次数都很高,可能是洗盘
    if buyCount > 50 && sellCount > 50 {
        return errors.New("potential wash trading detected")
    }

    return nil
}

3.3 异常提现检测

type WithdrawalRiskDetector struct {
    db    *sql.DB
    redis *redis.Client
}

func (wrd *WithdrawalRiskDetector) CheckWithdrawal(w *Withdrawal) error {
    // 1. 黑名单地址检测
    if wrd.isBlacklistedAddress(w.ToAddress) {
        return errors.New("blacklisted address")
    }

    // 2. 异常金额检测
    avgAmount, err := wrd.getUserAvgWithdrawal(w.UserID, w.Currency)
    if err == nil && w.Amount > avgAmount*10 {
        // 金额超过平均值10倍,需要人工审核
        w.Status = "reviewing"
        wrd.sendAlertToOps(w, "Large withdrawal detected")
    }

    // 3. 频率检测
    count, err := wrd.getWithdrawalCount24h(w.UserID)
    if err == nil && count > 10 {
        return errors.New("too many withdrawals in 24h")
    }

    // 4. 新地址检测
    if !wrd.hasUsedAddress(w.UserID, w.ToAddress) {
        // 新地址,延迟24小时
        w.Status = "pending_24h"
        wrd.sendAlertToUser(w.UserID, "New withdrawal address, 24h delay")
    }

    // 5. 设备指纹检测
    if wrd.isNewDevice(w.UserID, w.DeviceFingerprint) {
        w.Status = "reviewing"
        wrd.sendAlertToUser(w.UserID, "Withdrawal from new device")
    }

    return nil
}

func (wrd *WithdrawalRiskDetector) isBlacklistedAddress(address string) bool {
    // 查询黑名单数据库
    var count int
    wrd.db.QueryRow("SELECT COUNT(*) FROM blacklist_addresses WHERE address = ?", address).Scan(&count)
    return count > 0
}

4. 钱包安全

4.1 冷热钱包分离

资金分布策略:
┌──────────────────────────────────────────────────────────┐
│  热钱包 (5%)                                              │
│  - 处理充值提现                                            │
│  - 在线签名                                                │
│  - 风险最高                                                │
└──────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────┐
│  温钱包 (25%)                                             │
│  - 定期补充热钱包                                          │
│  - 半离线签名                                              │
│  - 需要人工操作                                            │
└──────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────┐
│  冷钱包 (70%)                                             │
│  - 长期存储                                                │
│  - 完全离线                                                │
│  - 多重签名                                                │
└──────────────────────────────────────────────────────────┘

热钱包自动归集:

type WalletManager struct {
    hotWallet  *Wallet
    warmWallet *Wallet
    coldWallet *Wallet
}

func (wm *WalletManager) AutoCollect() {
    ticker := time.NewTicker(1 * time.Hour)
    defer ticker.Stop()

    for range ticker.C {
        // 检查热钱包余额
        balance := wm.hotWallet.GetBalance("BTC")

        // 如果热钱包余额超过阈值,归集到温钱包
        if balance > 10 { // 10 BTC
            amount := balance - 5 // 保留5 BTC
            wm.transferToWarm("BTC", amount)
        }

        // 如果热钱包余额不足,从温钱包补充
        if balance < 2 {
            amount := 3 // 补充到5 BTC
            wm.transferFromWarm("BTC", amount)
        }
    }
}

func (wm *WalletManager) transferToWarm(currency string, amount float64) error {
    // 1. 创建交易
    tx, err := wm.hotWallet.CreateTransaction(wm.warmWallet.Address, amount)
    if err != nil {
        return err
    }

    // 2. 签名
    signedTx, err := wm.hotWallet.SignTransaction(tx)
    if err != nil {
        return err
    }

    // 3. 广播
    txid, err := wm.hotWallet.BroadcastTransaction(signedTx)
    if err != nil {
        return err
    }

    log.Printf("Transferred %f %s to warm wallet, txid: %s", amount, currency, txid)

    return nil
}

4.2 多重签名

2-of-3多签方案:

// Ethereum多签钱包合约
pragma solidity ^0.8.0;

contract MultiSigWallet {
    address[] public owners;
    uint public required;

    struct Transaction {
        address to;
        uint value;
        bytes data;
        bool executed;
        mapping(address => bool) confirmations;
        uint confirmationCount;
    }

    Transaction[] public transactions;

    modifier onlyOwner() {
        bool isOwner = false;
        for (uint i = 0; i < owners.length; i++) {
            if (owners[i] == msg.sender) {
                isOwner = true;
                break;
            }
        }
        require(isOwner, "Not an owner");
        _;
    }

    constructor(address[] memory _owners, uint _required) {
        require(_owners.length > 0, "Owners required");
        require(_required > 0 && _required <= _owners.length, "Invalid required number");

        owners = _owners;
        required = _required;
    }

    function submitTransaction(address _to, uint _value, bytes memory _data)
        public
        onlyOwner
        returns (uint)
    {
        uint txId = transactions.length;

        Transaction storage newTx = transactions.push();
        newTx.to = _to;
        newTx.value = _value;
        newTx.data = _data;
        newTx.executed = false;
        newTx.confirmationCount = 0;

        return txId;
    }

    function confirmTransaction(uint _txId) public onlyOwner {
        Transaction storage transaction = transactions[_txId];

        require(!transaction.executed, "Transaction already executed");
        require(!transaction.confirmations[msg.sender], "Already confirmed");

        transaction.confirmations[msg.sender] = true;
        transaction.confirmationCount++;

        // 如果确认数达到要求,自动执行
        if (transaction.confirmationCount >= required) {
            executeTransaction(_txId);
        }
    }

    function executeTransaction(uint _txId) public {
        Transaction storage transaction = transactions[_txId];

        require(transaction.confirmationCount >= required, "Not enough confirmations");
        require(!transaction.executed, "Already executed");

        transaction.executed = true;

        (bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
        require(success, "Transaction failed");
    }

    receive() external payable {}
}

4.3 私钥管理

分片存储:

import "github.com/hashicorp/vault/shamir"

type KeyManager struct{}

// 将私钥分成N份,需要M份才能恢复
func (km *KeyManager) SplitPrivateKey(privateKey []byte, n, m int) ([][]byte, error) {
    // Shamir秘密分享算法
    shares, err := shamir.Split(privateKey, n, m)
    if err != nil {
        return nil, err
    }

    return shares, nil
}

// 恢复私钥
func (km *KeyManager) RecoverPrivateKey(shares [][]byte) ([]byte, error) {
    privateKey, err := shamir.Combine(shares)
    if err != nil {
        return nil, err
    }

    return privateKey, nil
}

// 使用示例:3-of-5分片
func main() {
    km := &KeyManager{}

    privateKey := []byte("very_secret_private_key_32bytes!")

    // 分成5份,需要3份才能恢复
    shares, err := km.SplitPrivateKey(privateKey, 5, 3)
    if err != nil {
        panic(err)
    }

    // 分别存储到不同位置
    // Share 1: 云端HSM
    // Share 2: 本地加密文件
    // Share 3: U盘
    // Share 4: 纸质备份
    // Share 5: 合作伙伴保管

    // 恢复私钥(使用任意3份)
    recoveredKey, err := km.RecoverPrivateKey(shares[0:3])
    if err != nil {
        panic(err)
    }

    fmt.Printf("Recovered: %s\n", string(recoveredKey))
}

5. 审计日志

5.1 操作审计

type AuditLogger struct {
    db *sql.DB
}

type AuditLog struct {
    ID         int64
    UserID     int64
    Action     string
    Resource   string
    ResourceID string
    IPAddress  string
    UserAgent  string
    RequestID  string
    Details    string
    CreatedAt  time.Time
}

func (al *AuditLogger) Log(userID int64, action, resource, resourceID string, r *http.Request, details map[string]interface{}) {
    detailsJSON, _ := json.Marshal(details)

    _, err := al.db.Exec(`
        INSERT INTO audit_logs (user_id, action, resource, resource_id, ip_address, user_agent, request_id, details, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())
    `, userID, action, resource, resourceID,
        getClientIP(r),
        r.UserAgent(),
        r.Header.Get("X-Request-ID"),
        string(detailsJSON),
    )

    if err != nil {
        log.Printf("Failed to write audit log: %v", err)
    }
}

// 使用示例
func PlaceOrderHandler(w http.ResponseWriter, r *http.Request) {
    userID := getUserID(r)
    order := parseOrder(r)

    // 下单
    err := orderService.PlaceOrder(order)

    // 记录审计日志
    auditLogger.Log(userID, "place_order", "order", order.OrderID, r, map[string]interface{}{
        "symbol":   order.Symbol,
        "side":     order.Side,
        "price":    order.Price,
        "quantity": order.Quantity,
        "success":  err == nil,
    })

    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    json.NewEncoder(w).Encode(order)
}

5.2 敏感操作记录

// 记录敏感操作
func (al *AuditLogger) LogSensitiveOperation(userID int64, operation string, r *http.Request) {
    // 发送实时告警
    alert := fmt.Sprintf("User %d performed sensitive operation: %s", userID, operation)
    sendAlertToOps(alert)

    // 记录到专门的敏感操作表
    al.db.Exec(`
        INSERT INTO sensitive_operations (user_id, operation, ip_address, user_agent, device_fingerprint, created_at)
        VALUES (?, ?, ?, ?, ?, NOW())
    `, userID, operation, getClientIP(r), r.UserAgent(), getDeviceFingerprint(r))
}

// 敏感操作示例
func WithdrawHandler(w http.ResponseWriter, r *http.Request) {
    userID := getUserID(r)

    // 记录敏感操作
    auditLogger.LogSensitiveOperation(userID, "withdraw", r)

    // 处理提现
    // ...
}

小结

本章介绍了交易所的安全防护:

  1. 网络层防护:DDoS防护、SYN Flood、HTTP Flood、WAF规则
  2. 应用层防护:SQL注入、XSS、CSRF防护
  3. 业务层防护:订单重放、价格操纵检测、异常提现检测
  4. 钱包安全:冷热分离、多重签名、私钥分片管理
  5. 审计日志:操作审计、敏感操作记录

下一章将讲解压力测试与性能优化。

Prev
监控与告警系统
Next
高可用架构设计