安全防护与攻防
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>"
// 输出:<script>alert('XSS')</script>
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)
// 处理提现
// ...
}
小结
本章介绍了交易所的安全防护:
- 网络层防护:DDoS防护、SYN Flood、HTTP Flood、WAF规则
- 应用层防护:SQL注入、XSS、CSRF防护
- 业务层防护:订单重放、价格操纵检测、异常提现检测
- 钱包安全:冷热分离、多重签名、私钥分片管理
- 审计日志:操作审计、敏感操作记录
下一章将讲解压力测试与性能优化。