网络安全
#网络 · #安全 · #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 ACCEPT1.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 drop2. 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 吸收、多级缓存、弹性扩容 |
2.3 SYN Cookie
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 REJECT3. 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 |
| VXLAN | Overlay 网络,封装 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: 80806. 应用层攻击与防护
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> → <script>
// ❌ 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
}6.5 安全 Cookie 实践
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"]
endZero 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 -.->|"授权决策"| ServiceByaml
# 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 中的 token | HttpOnly Cookie 存储 |
| 暴力破解 | 弱密钥可被暴力破解 | 使用 RSA 2048+ 或 ES256 |
| Replay 攻击 | 重放有效 token | 短过期 + jti 唯一标识 |
登录后即可发表评论 👇