# 支付安全与合规指南 (Security & Compliance) v4.0

> 支付系统安全最佳实践，保护你的资金和用户数据

## 🔐 密钥安全

### 1. 密钥存储原则

```
❌ 错误做法:
- 将密钥硬编码在代码中
- 将密钥提交到 Git 仓库
- 通过即时通讯工具传输密钥
- 使用弱密码作为 API Key

✅ 正确做法:
- 使用环境变量存储密钥
- 使用专业密钥管理服务 (AWS KMS, HashiCorp Vault)
- 定期轮换密钥
- 最小权限原则
```

### 2. .gitignore 必须包含

```gitignore
# 支付密钥相关
.env
.env.local
.env.*.local
*.pem
*.key
cert/
config/payment.yml
secrets/
```

### 3. 密钥轮换

- 定期更换 API 密钥 (建议每 90 天)
- 发现泄露立即作废并重新生成
- 保留旧密钥短暂过渡期

---

## 🔒 通信安全

### 1. HTTPS 强制

```nginx
# Nginx 配置示例
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;
    
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
```

### 2. 证书管理

- 使用受信任的 CA 签发证书
- 定期检查证书有效期
- 推荐 Let's Encrypt 自动续期

---

## ✅ 签名验证

### 1. 支付宝签名验证

```python
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
import base64

def verify_alipay_sign(params: dict, sign: str, public_key: str) -> bool:
    """验证支付宝签名"""
    # 1. 参数排序
    sorted_params = sorted([(k, v) for k, v in params.items() if k != 'sign' and v])
    
    # 2. 拼接待签名字符串
    sign_str = '&'.join([f'{k}={v}' for k, v in sorted_params])
    
    # 3. RSA2 验签
    key = RSA.import_key(f"-----BEGIN PUBLIC KEY-----\n{public_key}\n-----END PUBLIC KEY-----")
    verifier = PKCS1_v1_5.new(key)
    hash_obj = SHA256.new(sign_str.encode('utf-8'))
    
    try:
        verifier.verify(hash_obj, base64.b64decode(sign))
        return True
    except (ValueError, TypeError):
        return False
```

### 2. 微信签名验证

```python
import hashlib

def verify_wechat_sign(params: dict, sign: str, api_key: str) -> bool:
    """验证微信支付签名"""
    # 1. 参数排序
    sorted_params = sorted([(k, v) for k, v in params.items() if k != 'sign' and v])
    
    # 2. 拼接待签名字符串
    sign_str = '&'.join([f'{k}={v}' for k, v in sorted_params])
    sign_str += f'&key={api_key}'
    
    # 3. MD5 签名
    calculated_sign = hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
    
    return calculated_sign == sign
```

---

## 💰 金额校验

### 1. 回调金额必须验证

```python
def handle_payment_notify(trade_sn: str, paid_amount: int):
    """处理支付回调时必须验证金额"""
    trade = get_trade_by_sn(trade_sn)
    
    # 金额必须严格匹配
    if paid_amount != trade.cash_amount:
        log.error(f"金额不匹配! 订单:{trade.cash_amount}, 回调:{paid_amount}")
        raise AmountMismatchError()
    
    # 继续处理...
```

### 2. 防止金额篡改

```python
# 前端传入的金额仅用于展示，实际金额从后端订单读取
def checkout(order_sn: str, gateway: str):
    order = get_order(order_sn)
    
    # 金额从数据库读取，不信任前端
    amount = order.pay_amount
    
    return create_trade(order_sn, amount, gateway)
```

---

## 🛡️ 回调安全

### 1. IP 白名单

```python
# 支付平台回调 IP 白名单
PAYMENT_IP_WHITELIST = {
    'alipay': [
        '110.75.0.0/16',
        '203.209.0.0/16'
    ],
    'wechat': [
        '101.226.0.0/16',
        '140.207.0.0/16'
    ]
}

def verify_callback_ip(gateway: str, client_ip: str) -> bool:
    """验证回调来源 IP"""
    import ipaddress
    
    whitelist = PAYMENT_IP_WHITELIST.get(gateway, [])
    client = ipaddress.ip_address(client_ip)
    
    for cidr in whitelist:
        if client in ipaddress.ip_network(cidr):
            return True
    
    return False
```

### 2. 防重放攻击

```python
import time

def check_notify_timestamp(timestamp: int) -> bool:
    """检查回调时间戳，防止重放攻击"""
    now = int(time.time())
    
    # 允许 5 分钟的时间差
    if abs(now - timestamp) > 300:
        log.warning(f"回调时间戳异常: {timestamp}")
        return False
    
    return True
```

### 3. 幂等性处理

```python
def process_notify_idempotent(trade_sn: str, notify_data: dict):
    """幂等性处理回调"""
    
    # 使用分布式锁
    lock_key = f"payment_notify:{trade_sn}"
    
    with redis_lock(lock_key, timeout=10):
        trade = get_trade_by_sn(trade_sn)
        
        # 已处理过，直接返回成功
        if trade.status == 'paid':
            return success_response()
        
        # 处理支付成功逻辑
        update_trade_to_paid(trade, notify_data)
        
    return success_response()
```

---

## 📝 日志审计

### 1. 必须记录的日志

```python
import logging

payment_logger = logging.getLogger('payment')

# 创建交易日志
payment_logger.info(f"创建交易 | trade_sn={trade_sn} | order_sn={order_sn} | amount={amount} | gateway={gateway}")

# 回调日志
payment_logger.info(f"收到回调 | gateway={gateway} | trade_sn={trade_sn} | raw_data={raw_data[:500]}")

# 签名验证日志
payment_logger.info(f"签名验证 | trade_sn={trade_sn} | result={verify_result}")

# 状态变更日志
payment_logger.info(f"状态变更 | trade_sn={trade_sn} | from={old_status} | to={new_status}")

# 退款日志
payment_logger.info(f"发起退款 | refund_sn={refund_sn} | trade_sn={trade_sn} | amount={amount}")
```

### 2. 敏感信息脱敏

```python
def mask_sensitive(data: dict) -> dict:
    """敏感信息脱敏"""
    sensitive_keys = ['card_no', 'id_card', 'phone', 'bank_account']
    
    masked = data.copy()
    for key in sensitive_keys:
        if key in masked:
            value = str(masked[key])
            if len(value) > 4:
                masked[key] = value[:2] + '*' * (len(value) - 4) + value[-2:]
    
    return masked
```

---

## 🚨 异常处理

### 1. 支付异常分类

```python
class PaymentError(Exception):
    """支付基础异常"""
    pass

class SignatureError(PaymentError):
    """签名验证失败"""
    pass

class AmountMismatchError(PaymentError):
    """金额不匹配"""
    pass

class OrderExpiredError(PaymentError):
    """订单已过期"""
    pass

class DuplicatePaymentError(PaymentError):
    """重复支付"""
    pass

class RefundError(PaymentError):
    """退款失败"""
    pass
```

### 2. 统一异常处理

```python
@app.exception_handler(PaymentError)
async def payment_exception_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={
            "code": 400,
            "message": str(exc),
            "data": None
        }
    )
```

---

## ✅ 合规要求

### 1. PCI DSS 合规 (信用卡)

- 不存储完整卡号、CVV、PIN
- 使用 Stripe/PayPal 等符合 PCI DSS 的支付网关
- 定期安全评估

### 2. GDPR 合规 (欧盟用户)

- 明确告知用户数据用途
- 提供数据删除功能
- 用户同意授权

### 3. 中国支付合规

- 接入持牌支付机构
- 实名认证
- 交易限额管理

---

## 📋 安全检查清单

```markdown
## 上线前安全检查

### 密钥管理
- [ ] 所有密钥通过环境变量配置
- [ ] 密钥未提交到代码仓库
- [ ] 生产环境密钥与测试环境隔离

### 通信安全
- [ ] 启用 HTTPS
- [ ] 证书有效且受信任
- [ ] 启用 HSTS

### 签名验证
- [ ] 所有回调验签
- [ ] 验签失败拒绝处理

### 金额校验
- [ ] 回调金额与订单金额比对
- [ ] 金额从后端读取

### 日志审计
- [ ] 关键操作有日志
- [ ] 敏感信息脱敏

### 异常处理
- [ ] 异常不泄露敏感信息
- [ ] 有统一异常处理

### 回调安全
- [ ] IP 白名单验证 (可选)
- [ ] 幂等性处理
- [ ] 防重放攻击
```
