Skip to content

网络安全 ​

#网络 · #安全 · #iptables · #DDoS · #防火墙 · #网络隔离

网络安全不是锦上添花,而是基础设施。从 iptables 防火墙规则到 TLS 加密,从 DDoS 防护到网络隔离,理解网络层的安全机制是后端工程师的必修课。


1. iptables / nftables ​

1.1 四表五链 ​

mermaid
flowchart LR
    IN["入站包"] --> PREROUTING["PREROUTING<br/>(raw→mangle→nat)"]
    PREROUTING --> ROUTE{"路由决策"}
    ROUTE -->|"本机"| INPUT["INPUT<br/>(mangle→filter)"]
    INPUT --> PROCESS["用户进程"]
    ROUTE -->|"转发"| FORWARD["FORWARD<br/>(mangle→filter)"]
    FORWARD --> POSTROUTING["POSTROUTING<br/>(mangle→nat)"]
    PROCESS --> OUTPUT["OUTPUT<br/>(raw→mangle→nat→filter)"]
    OUTPUT --> POSTROUTING
    POSTROUTING --> OUT["出站包"]

    NOTE["表优先级: raw → mangle → nat → filter<br/>(同一链上按此顺序执行)"]
    OUT -.-> NOTE
表用途链
filter包过滤(默认表)INPUT, OUTPUT, FORWARD
nat地址转换PREROUTING, OUTPUT, POSTROUTING
mangle修改包头(TTL, TOS)全部 5 条链
raw跳过连接跟踪PREROUTING, OUTPUT

1.2 常用规则 ​

bash
# 查看规则
iptables -L -n -v                    # filter 表
iptables -t nat -L -n -v             # nat 表

# 允许/拒绝流量
iptables -A INPUT -p tcp --dport 22 -j ACCEPT     # 允许 SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT     # 允许 HTTP
iptables -A INPUT -j DROP                          # 默认拒绝

# 端口转发(DNAT)
iptables -t nat -A PREROUTING -p tcp --dport 80 \
    -j DNAT --to-destination 10.0.0.5:8080

# 源地址转换(SNAT / MASQUERADE)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 \
    -o eth0 -j MASQUERADE

# 连接限制
iptables -A INPUT -p tcp --dport 80 \
    -m connlimit --connlimit-above 100 -j REJECT

# 速率限制
iptables -A INPUT -p tcp --dport 80 \
    -m limit --limit 25/minute --limit-burst 100 -j ACCEPT

1.3 nftables(iptables 的继任者) ​

bash
# nftables 统一了 iptables/ip6tables/arptables/ebtables
nft add table inet my_filter
nft add chain inet my_filter input { type filter hook input priority 0\; }
nft add rule inet my_filter input tcp dport 22 accept
nft add rule inet my_filter input drop

2. DDoS 防护 ​

2.1 常见攻击类型 ​

攻击类型原理特征
SYN Flood发送大量 SYN,不完成握手大量 SYN_RECV 状态连接
UDP Flood发送大量 UDP 包带宽打满
HTTP Flood发送大量 HTTP 请求正常请求,难以区分
DNS Amplification伪造源 IP 发 DNS 查询放大 50~100 倍流量
Slowloris慢速发送 HTTP Header占用连接,低带宽
CC 攻击针对动态页面的高频请求数据库/缓存压力

2.2 防护手段 ​

层次手段
网络层SYN Cookie、黑洞路由(Remotely Triggered Black Hole)、Anycast 分散
传输层连接限速、SYN Proxy、IP 信誉库
应用层WAF、验证码、频率限制、JS Challenge
架构层CDN 吸收、多级缓存、弹性扩容
bash
# Linux 内核默认开启
sysctl net.ipv4.tcp_syncookies=1

# 原理:收到 SYN 时不立即分配资源,
# 而是将连接信息编码到 ISN (Initial Sequence Number) 中。
# 收到 ACK 时再解码验证,验证通过才真正建立连接。

2.4 限速配置 ​

bash
# 限制 SYN 速率
iptables -A INPUT -p tcp --syn -m limit --limit 100/s -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

# 限制单个 IP 的连接数
iptables -A INPUT -p tcp --dport 80 -m connlimit \
    --connlimit-above 50 --connlimit-mask 32 -j REJECT

3. TLS / mTLS ​

TLS 基础见 HTTPS 与 TLS。这里聚焦网络安全视角。

3.1 mTLS(双向 TLS) ​

普通 TLS:         Client → 验证 Server 证书 → 加密通信
mTLS:             Client ↔ 互相验证证书 ↔ 加密通信
nginx
# Nginx mTLS 配置
server {
    listen 443 ssl;
    ssl_certificate     /path/to/server.crt;
    ssl_certificate_key /path/to/server.key;

    ssl_client_certificate /path/to/ca.crt;  # 客户端 CA
    ssl_verify_client on;                     # 验证客户端证书
    ssl_verify_depth 2;
}

3.2 证书固定(Certificate Pinning) ​

首次连接 → 存储服务器公钥指纹
后续连接 → 对比指纹 → 不匹配 → 拒绝(防中间人)

风险:证书轮换时可能导致大面积故障。更推荐使用 Certificate Transparency + 短生命周期证书。


4. VPN 与隧道 ​

协议特点适用场景
WireGuard极简(4000 行代码)、高性能、内核态现代化 VPN 首选
IPSec标准协议、复杂配置企业站点互联
OpenVPN用户态、跨平台、成熟传统 VPN
VXLANOverlay 网络,封装 L2 到 UDP容器网络(Flannel/Calico)
GRE通用隧道协议简单隧道需求

4.1 WireGuard 特点 ​

  • 使用 Noise 协议框架 + ChaCha20 + Poly1305 + Curve25519
  • 漫游支持:IP 地址变化后自动恢复
  • 加密密钥路由:每个 peer 有固定密钥 → 天然身份认证

5. 网络隔离 ​

5.1 VLAN(二层隔离) ​

交换机端口 → VLAN ID → 不同 VLAN 间默认不互通
跨 VLAN 通信 → 路由器 / 三层交换机

5.2 VPC / 安全组(云环境) ​

bash
# AWS 安全组示例
Ingress:
  TCP 80   from 0.0.0.0/0        # 公网 HTTP
  TCP 22   from 10.0.0.0/8       # 仅内网 SSH
  TCP 5432 from sg-database      # 仅数据库安全组访问

Egress:
  All from 0.0.0.0/0             # 允许所有出站

5.3 Network Policy(Kubernetes) ​

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

6. 应用层攻击与防护 ​

6.1 SQL 注入 ​

sql
-- 正常查询
SELECT * FROM users WHERE name = 'Alice'

-- 恶意输入:' OR '1'='1
SELECT * FROM users WHERE name = '' OR '1'='1'
-- → 返回所有用户!

-- 恶意输入:'; DROP TABLE users; --
SELECT * FROM users WHERE name = ''; DROP TABLE users; --'

防护:

go
// ❌ 拼接字符串
db.Exec("SELECT * FROM users WHERE name = '" + name + "'")

// ✅ 参数化查询
db.Exec("SELECT * FROM users WHERE name = ?", name)

// Go 的 database/sql 使用 ? 占位符 → 驱动自动转义

6.2 XSS(跨站脚本攻击) ​

存储型 XSS:
  攻击者提交 <script>alert('hacked')</script> 到评论
  → 存入 DB
  → 其他用户访问页面 → 脚本执行

反射型 XSS:
  攻击者构造 URL: /search?q=<script>...</script>
  → 服务端把参数原样输出到 HTML
  → 脚本执行

防护:

go
// 输出转义(Go html/template 默认转义)
import "html/template"

// ✅ html/template 自动转义
tmpl.Execute(w, userInput) // <script> → &lt;script&gt;

// ❌ text/template 不转义
textTemplate.Execute(w, userInput) // 危险!

// HTTP 头防护
w.Header().Set("Content-Security-Policy", "default-src 'self'")
w.Header().Set("X-XSS-Protection", "1; mode=block")

6.3 CSRF(跨站请求伪造) ​

场景:
  用户已登录 bank.com(Cookie 有效)
  用户访问 evil.com
  evil.com 中的 <form> 自动提交到 bank.com/transfer?to=evil&amount=10000
  → 浏览器自动带 Cookie,请求被 bank.com 认为是合法请求

防护:

go
// 1. CSRF Token
// 服务端生成随机 Token,嵌入表单,提交时校验

// 2. SameSite Cookie
http.SetCookie(w, &http.Cookie{
    Name:     "session",
    Value:    sessionID,
    SameSite: http.SameSiteStrictMode, // 或 LaxMode
})

// 3. 检查 Referer/Origin 头
origin := r.Header.Get("Origin")

// 4. 关键操作要求二次验证(输入密码/验证码)
SameSite行为
Strict完全禁止跨站发送 Cookie
Lax允许 GET 导航请求(如点击链接),禁止 POST
None不限制(需配合 Secure)

6.4 SSRF(服务端请求伪造) ​

攻击者控制 URL 参数
  → 服务端发起请求到内网地址
  → 扫描/攻击内网服务

例:/fetch?url=http://169.254.169.254/latest/meta-data/
  → AWS EC2 元数据泄露

防护:

go
func safeFetch(rawURL string) error {
    u, err := url.Parse(rawURL)
    if err != nil {
        return err
    }

    // 禁止内网 IP
    ip := net.ParseIP(u.Hostname())
    if ip != nil && ip.IsPrivate() {
        return fmt.Errorf("private IP not allowed")
    }

    // 白名单域名
    if u.Host != "api.example.com" {
        return fmt.Errorf("host not allowed")
    }

    // 禁止 file:// 等协议
    if u.Scheme != "http" && u.Scheme != "https" {
        return fmt.Errorf("scheme not allowed")
    }
    return nil
}
go
http.SetCookie(w, &http.Cookie{
    Name:     "session_id",
    Value:    sessionID,
    Path:     "/",
    Domain:   "example.com",
    HttpOnly: true,   // 禁止 JS 读取(防 XSS 窃取)
    Secure:   true,   // 仅 HTTPS 传输
    SameSite: http.SameSiteLaxMode,
    MaxAge:   3600,
})

7. 安全排查清单 ​

检查项命令 / 方法
开放端口ss -tlnp / nmap -sT localhost
异常连接ss -tanp | grep ESTAB | awk '{print $5}' | sort | uniq -c | sort -rn
防火墙规则iptables -L -n -v
异常流量iftop / nethogs
登录记录last -20 / lastb -20

参考 ​


8. Zero Trust 架构 ​

传统边界安全 vs Zero Trust ​

mermaid
flowchart TB
    subgraph Traditional["传统边界安全模型"]
        FW["防火墙<br/>(城墙)"]
        Inside["内网<br/>(信任区域)<br/>内部通信无验证"]
        Outside["外网<br/>(不信任)"]
        Outside -->|"验证"| FW -->|"放行"| Inside
        Note1["问题:一旦攻破边界<br/>内部横向移动无阻碍"]
    end

    subgraph ZeroTrust["Zero Trust 模型"]
        ZT1["每次请求都验证<br/>Never Trust, Always Verify"]
        ZT2["最小权限原则<br/>只授予必要权限"]
        ZT3["持续验证<br/>身份+设备+上下文"]
        ZT4["微分段<br/>服务间 mTLS"]
    end

Zero Trust 核心原则 ​

原则说明实现方式
永不信任不因为在"内网"就信任每次请求都要认证+授权
最小权限只给必要的最小权限RBAC + 细粒度策略
持续验证不是一次认证永久有效短生命周期 Token + 持续评估
假设被入侵设计时假设已被攻破微分段 + 加密 + 审计日志

微服务中的 Zero Trust 实现 ​

mermaid
flowchart TB
    Client["客户端"] -->|"1. OAuth2 认证"| Gateway["API Gateway<br/>(验证 JWT)"]
    Gateway -->|"2. mTLS + JWT"| ServiceA["Service A"]
    ServiceA -->|"3. mTLS + JWT"| ServiceB["Service B"]
    ServiceB -->|"4. mTLS"| DB["Database"]

    subgraph Mesh["Service Mesh (Istio)"]
        ServiceA
        ServiceB
    end

    Policy["OPA 策略引擎"] -.->|"授权决策"| ServiceA
    Policy -.->|"授权决策"| ServiceB
yaml
# Istio AuthorizationPolicy(服务间访问控制)
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: order-service-policy
spec:
  selector:
    matchLabels:
      app: order-service
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/payment-service"]
    to:
    - operation:
        methods: ["POST"]
        paths: ["/api/orders/*/pay"]
  # 只有 payment-service 可以调用订单支付接口

9. OAuth2 / JWT 安全实践 ​

OAuth2 授权流程 ​

mermaid
sequenceDiagram
    participant User as 用户
    participant Client as 客户端应用
    participant AuthServer as 授权服务器
    participant Resource as 资源服务器

    User->>Client: 1. 点击"登录"
    Client->>AuthServer: 2. 重定向到授权页<br/>(client_id, redirect_uri, scope, state)
    User->>AuthServer: 3. 输入账号密码,同意授权
    AuthServer->>Client: 4. 重定向回 redirect_uri<br/>(authorization_code)
    Client->>AuthServer: 5. 用 code 换 token<br/>(code, client_secret)
    AuthServer->>Client: 6. 返回 access_token + refresh_token
    Client->>Resource: 7. 携带 access_token 访问资源
    Resource->>Resource: 8. 验证 token(签名+过期+权限)
    Resource->>Client: 9. 返回数据

JWT 结构与安全 ​

JWT = Header.Payload.Signature

Header:  {"alg": "RS256", "typ": "JWT", "kid": "key-2024"}
Payload: {"sub": "user123", "exp": 1720000000, "iss": "auth.example.com", "roles": ["admin"]}
Signature: RS256(base64(header) + "." + base64(payload), private_key)

JWT 安全最佳实践 ​

实践说明原因
使用 RS256 而非 HS256非对称签名资源服务器只需公钥验证,不持有密钥
短生命周期access_token 15-30 分钟泄漏后影响时间有限
Refresh Token 轮换每次刷新生成新 refresh_token防止 refresh_token 被盗用
不存敏感信息Payload 是 Base64 编码(非加密)任何人都能解码看到内容
验证所有字段iss, aud, exp, nbf 都要验证防止 token 被跨服务滥用
使用 kid 轮换密钥Header 中指定密钥 ID支持密钥轮换不中断服务

Go JWT 验证实现 ​

go
import "github.com/golang-jwt/jwt/v5"

// 验证 JWT(资源服务器)
func ValidateToken(tokenString string) (*Claims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
        // 验证签名算法(防止 alg=none 攻击)
        if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }

        // 根据 kid 获取对应公钥
        kid := token.Header["kid"].(string)
        publicKey, err := getPublicKey(kid)  // 从 JWKS 端点获取
        if err != nil {
            return nil, err
        }
        return publicKey, nil
    })

    if err != nil {
        return nil, err
    }

    claims := token.Claims.(*Claims)

    // 额外验证
    if claims.Issuer != "auth.example.com" {
        return nil, fmt.Errorf("invalid issuer")
    }
    if !contains(claims.Audience, "my-service") {
        return nil, fmt.Errorf("invalid audience")
    }

    return claims, nil
}

// Token 刷新策略
type TokenPair struct {
    AccessToken  string `json:"access_token"`
    RefreshToken string `json:"refresh_token"`
    ExpiresIn    int    `json:"expires_in"`
}

func RefreshTokens(refreshToken string) (*TokenPair, error) {
    // 1. 验证 refresh_token
    claims, err := validateRefreshToken(refreshToken)
    if err != nil {
        return nil, err
    }

    // 2. 检查是否已被使用(Refresh Token Rotation)
    if isTokenUsed(refreshToken) {
        // 可能被盗!撤销该用户所有 token
        revokeAllTokens(claims.UserID)
        return nil, fmt.Errorf("refresh token reuse detected")
    }

    // 3. 标记旧 token 为已使用
    markTokenUsed(refreshToken)

    // 4. 生成新的 token pair
    return generateTokenPair(claims.UserID, claims.Roles)
}

常见 JWT 攻击与防护 ​

攻击原理防护
alg=none将算法改为 none,跳过签名验证服务端强制验证算法类型
密钥混淆RS256→HS256,用公钥作为 HMAC 密钥验证 alg 必须是预期值
Token 泄漏XSS 窃取 localStorage 中的 tokenHttpOnly Cookie 存储
暴力破解弱密钥可被暴力破解使用 RSA 2048+ 或 ES256
Replay 攻击重放有效 token短过期 + jti 唯一标识
批注模式

💬 文章评论

暂无评论,来说点什么吧 👇

编程学习笔记