lolly/docs/09-nginx-security.md
xfy d6367a1c38 feat(http3,docs,middleware): 实现 Phase 9 HTTP/3 与性能优化扩展
- 新增 HTTP/3 (QUIC) 服务器支持,集成到 App 生命周期管理
- 新增 nginx 内置变量速查表文档
- 完善多篇 nginx 文档(代理、安全、流、限流、HTTP/2/3、核心事件)
- 新增一致性哈希负载均衡、gzip_static、滑动窗口限流中间件
- 扩展配置支持 HTTP/3 和日志格式选项

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-03 15:39:06 +08:00

735 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NGINX 安全与访问控制指南
## 1. 访问控制
### IP 访问控制
```nginx
# 允许/拒绝特定 IP
location /admin/ {
allow 192.168.1.0/24;
allow 10.0.0.1;
deny all;
}
# 仅允许本地访问内部接口
location /internal/ {
allow 127.0.0.1;
deny all;
}
```
### 地理位置访问控制GeoIP
```nginx
http {
geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $allowed_country {
default no;
CN yes;
US yes;
}
server {
if ($allowed_country = no) {
return 403;
}
}
}
```
---
## 2. 外部认证 (ngx_http_auth_request_module)
NGINX 的 `ngx_http_auth_request_module` 模块(从 NGINX 1.5.4+ 开始支持,需编译时启用)提供外部认证功能,允许通过发送子请求到认证服务来决定是否允许访问。
### 2.1 指令说明
| 指令 | 语法 | 默认值 | 上下文 |
|------|------|--------|--------|
| `auth_request` | `auth_request uri \| off;` | `off` | http, server, location |
| `auth_request_set` | `auth_request_set $variable value;` | — | http, server, location |
### 2.2 工作原理
1. **NGINX 发送子请求**当收到客户端请求时NGINX 向指定的认证 URI 发送子请求
2. **认证服务响应**:认证服务返回 HTTP 状态码200 表示通过401/403 表示拒绝)
3. **结果判定**
- 返回 200NGINX 继续处理原请求
- 返回 401/403NGINX 拒绝访问并返回相应状态码
- 其他状态码:视为错误,返回 500
**流程图**
```
Client → NGINX → auth_request (子请求)
认证服务
200 OK? → 是 → 处理原请求 → 后端服务
返回 401/403 → Client
```
### 2.3 基础配置示例
```nginx
server {
listen 80;
server_name api.example.com;
location /protected/ {
auth_request /auth;
proxy_pass http://backend;
}
# 认证子请求 location
location = /auth {
internal; # 仅限内部子请求访问
proxy_pass http://auth-server/verify;
proxy_pass_request_body off; # 不传递请求体到认证服务
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Client-IP $remote_addr;
}
}
```
### 2.4 带变量提取的认证
从认证服务响应中提取自定义头部到变量:
```nginx
server {
location /api/ {
auth_request /auth;
auth_request_set $auth_user $upstream_http_x_user;
auth_request_set $auth_role $upstream_http_x_role;
proxy_pass http://backend;
proxy_set_header X-User $auth_user;
proxy_set_header X-Role $auth_role;
}
location = /auth {
internal;
proxy_pass http://auth-service/verify;
proxy_pass_request_body off;
proxy_set_header Authorization $http_authorization;
}
}
```
**可用变量**
- `$upstream_http_*`:从认证服务响应中提取任意 HTTP 头部
- `$upstream_status`:认证服务返回的状态码
- `$upstream_response_time`:认证响应时间
### 2.5 JWT/OAuth2 集成示例
```nginx
server {
listen 443 ssl;
server_name api.example.com;
location /api/ {
auth_request /auth_jwt;
auth_request_set $jwt_claims $upstream_http_x_jwt_claims;
auth_request_set $jwt_sub $upstream_http_x_jwt_sub;
proxy_pass http://api_backend;
proxy_set_header X-JWT-Claims $jwt_claims;
proxy_set_header X-User-Id $jwt_sub;
# 自定义 401 响应
error_page 401 = @unauthorized;
}
location = /auth_jwt {
internal;
proxy_pass http://jwt-validator/verify;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Original-URI $request_uri;
proxy_pass_request_body off;
}
location @unauthorized {
default_type application/json;
return 401 '{"error":"Unauthorized","code":"INVALID_TOKEN"}';
}
}
```
### 2.6 多级认证组合
结合 `auth_request``auth_basic`
```nginx
server {
location /admin/ {
# 先进行基础认证
auth_basic "Admin Access";
auth_basic_user_file /etc/nginx/.htpasswd;
# 再进行外部权限校验
auth_request /auth_admin;
proxy_pass http://admin_backend;
}
location = /auth_admin {
internal;
proxy_pass http://permission-service/check-admin;
proxy_set_header X-User $remote_user;
}
}
```
### 2.7 错误处理
```nginx
server {
location /api/ {
auth_request /auth;
# 认证失败重定向到登录页
error_page 401 = @login;
proxy_pass http://backend;
}
location @login {
return 302 https://auth.example.com/login?redirect=$request_uri;
}
# 认证服务不可用时
error_page 500 = @auth_error;
location @auth_error {
return 503 '{"error":"Authentication service unavailable"}';
}
}
```
### 2.8 应用场景
| 场景 | 实现方式 |
|------|----------|
| **OAuth2/OIDC 集成** | 认证服务验证 access_token返回用户信息 |
| **JWT Token 验证** | 验证 JWT 签名和过期时间,提取 claims |
| **统一认证网关** | 集中处理多个服务的认证逻辑 |
| **权限分级验证** | 根据路径或资源进行细粒度权限检查 |
| **多因素认证** | 组合多种认证方式(密码 + 短信/邮件) |
| **API Key 验证** | 验证请求中的 API Key 有效性 |
### 2.9 最佳实践
**1. 认证服务高可用**
```nginx
upstream auth_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080 backup;
keepalive 32;
}
location = /auth {
internal;
proxy_pass http://auth_backend/verify;
proxy_connect_timeout 5s;
proxy_send_timeout 5s;
proxy_read_timeout 5s;
}
```
**2. 缓存认证结果**(减少重复验证)
```nginx
location /api/ {
auth_request /auth;
# 启用缓存(需配合 proxy_cache
proxy_cache auth_cache;
proxy_cache_valid 200 1m;
proxy_pass http://backend;
}
```
**3. 调试认证流程**
```nginx
# 记录认证请求日志
log_format auth_log '$remote_addr - $time_local '
'auth_status=$auth_request_status '
'user=$auth_user';
access_log /var/log/nginx/auth.log auth_log;
```
---
## 3. HTTP 基础认证
### 配置认证
```nginx
location /admin/ {
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
```
### 创建密码文件
```bash
# 使用 htpasswd 创建
htpasswd -c /etc/nginx/.htpasswd user1
htpasswd /etc/nginx/.htpasswd user2
# 使用 openssl
echo "user1:$(openssl passwd -apr1 password1)" > /etc/nginx/.htpasswd
```
### 密码文件格式
```
# 注释
user1:encrypted_password1
user2:encrypted_password2:comment
```
**支持的密码类型**
- `crypt()` 加密
- MD5 哈希apr1
- `{scheme}data` 语法RFC 2307
### 组合访问控制
```nginx
location /admin/ {
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
# 认证通过后,还需 IP 白名单
satisfy any; # any 或 all
allow 192.168.1.0/24;
deny all;
}
```
---
## 4. 请求限制
### 请求速率限制
```nginx
http {
# 定义限制区域
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_req_zone $server_name zone=server_limit:10m rate=100r/s;
server {
location /api/ {
# 应用限制
limit_req zone=req_limit burst=20 nodelay;
limit_req zone=server_limit burst=50;
}
}
}
```
**参数说明**
| 参数 | 说明 |
|------|------|
| `zone=name:size` | 共享内存区域 |
| `rate=Nr/s` | 请求速率(每秒 N 个请求) |
| `burst=N` | 突发请求数量 |
| `nodelay` | 不延迟过量请求 |
| `delay=N` | 开始延迟的阈值 |
### 连接数限制
```nginx
http {
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /download/ {
limit_conn conn_limit 10; # 每个 IP 最多 10 个连接
limit_conn_status 503; # 超限返回 503
limit_conn_log_level warn; # 日志级别
}
}
}
```
### 综合限制示例
```nginx
http {
# 请求速率限制
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
# 连接数限制
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
# 全局限制
limit_req zone=req_limit burst=20 nodelay;
limit_conn conn_limit 20;
location /api/ {
# API 接口更严格
limit_req zone=req_limit burst=5 nodelay;
limit_conn conn_limit 5;
}
location /static/ {
# 静态资源不限制
limit_req off;
limit_conn off;
}
}
}
```
### Dry Run 模式(限流测试)
NGINX 支持限流 dry run 模式,用于测试限流配置而不实际拒绝请求:
```nginx
server {
location /api/ {
limit_req zone=req_limit burst=20 nodelay;
limit_req_dry_run on; # 请求不被拒绝,但记录日志
limit_conn conn_limit 10;
limit_conn_dry_run on; # 连接不被拒绝,但记录日志
proxy_pass http://backend;
}
}
```
**Dry Run 作用**
- 限流判断正常执行,但不返回 503/429 错误
- 记录 `limiting requests/connections, dry run` 到错误日志
- 用于评估限流阈值是否设置合理
> **注意**:详细限流配置请参考 [20-nginx-rate-limiting.md](./20-nginx-rate-limiting.md)
---
## 5. 安全头部
### 基础安全头部
```nginx
server {
# 隐藏版本号
server_tokens off;
# HSTS强制 HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 防止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" always;
# XSS 保护
add_header X-XSS-Protection "1; mode=block" always;
# 点击劫持保护
add_header X-Frame-Options "SAMEORIGIN" always;
# CSP
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;
# Referrer 策略
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 权限策略
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
}
```
### X-Frame-Options 选项
| 值 | 说明 |
|-----|------|
| `DENY` | 完全禁止 iframe 嵌入 |
| `SAMEORIGIN` | 仅允许同源 iframe |
| `ALLOW-FROM uri` | 允许指定来源(已废弃) |
---
## 6. 防盗链
### 基础防盗链
```nginx
location ~* \.(jpg|jpeg|png|gif|webp|flv|mp4|swf)$ {
valid_referers none blocked server_names *.example.com example.* ~\.google\.;
if ($invalid_referer) {
return 403;
# 或返回替代图片
# rewrite ^/.*$ /hotlink.png break;
}
}
```
### valid_referers 参数
| 参数 | 说明 |
|------|------|
| `none` | 缺少 Referer 头 |
| `blocked` | Referer 被 firewall 等删除 |
| `server_names` | server_name 中的域名 |
| `*.domain` | 通配符域名 |
| `~regex` | 正则表达式 |
---
## 7. SSL/TLS 安全
### 协议配置
```nginx
server {
listen 443 ssl;
server_name example.com;
# 仅启用安全协议
ssl_protocols TLSv1.2 TLSv1.3;
# 安全加密套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
# DH 参数
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# 会话配置
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
}
```
### 生成 DH 参数
```bash
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
```
---
## 8. 防止常见攻击
### SQL 注入防护
```nginx
# 阻止可疑请求
if ($request_uri ~* "(union|select|insert|drop|delete|update|cast|script|alert)") {
return 403;
}
# 或使用 ModSecurity 模块
```
### 防止目录遍历
```nginx
location ~* \.(git|svn|htpasswd|htaccess|env) {
deny all;
return 404;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
return 404;
}
```
### 限制请求方法
```nginx
location / {
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 405;
}
}
```
### 限制请求体大小
```nginx
http {
client_max_body_size 10m;
client_body_buffer_size 128k;
}
```
### 超时设置
```nginx
http {
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
}
```
---
## 9. 限制特定 User-Agent
```nginx
# 阻止恶意爬虫
if ($http_user_agent ~* (bot|crawl|spider|scraper)) {
return 403;
}
# 阻止特定工具
if ($http_user_agent ~* (wget|curl|python-requests|scrapy)) {
return 403;
}
# 使用 map 更优雅
map $http_user_agent $block_ua {
default 0;
~*bot 1;
~*crawl 1;
~*spider 1;
}
if ($block_ua) {
return 403;
}
```
---
## 10. WAF 配置ModSecurity
### 安装 ModSecurity
```bash
# Ubuntu/Debian
apt install libmodsecurity3 modsecurity-crs
# 加载模块
load_module modules/ngx_http_modsecurity_module.so;
```
### 配置示例
```nginx
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity.conf;
# 使用 OWASP Core Rule Set
modsecurity_rules '
Include /usr/share/modsecurity-crs/*.conf
Include /usr/share/modsecurity-crs/rules/*.conf
';
```
---
## 11. fail2ban 集成
### 创建 filter
```ini
# /etc/fail2ban/filter.d/nginx-limit-req.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*" (403|404|444|503).*$
ignoreregex =
```
### 创建 jail
```ini
# /etc/fail2ban/jail.local
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
port = http,https
logpath = /var/log/nginx/*error.log
findtime = 60
bantime = 3600
maxretry = 10
```
---
## 12. 安全配置检查清单
### 基础安全
- [ ] 隐藏版本号 (`server_tokens off`)
- [ ] 禁用 SSLv2/SSLv3/TLSv1.0/TLSv1.1
- [ ] 配置 HSTS
- [ ] 设置安全头部
- [ ] 禁用自动索引 (`autoindex off`)
- [ ] 禁止访问隐藏文件
### 访问控制
- [ ] 管理后台 IP 白名单
- [ ] 内部接口认证保护
- [ ] 敏感目录访问限制
### 请求限制
- [ ] 请求速率限制
- [ ] 连接数限制
- [ ] 请求体大小限制
- [ ] 请求超时设置
### SSL/TLS
- [ ] 使用 TLSv1.2/TLSv1.3
- [ ] 配置安全加密套件
- [ ] 启用 OCSP Stapling
- [ ] 配置 DH 参数
- [ ] 禁用会话票据(或轮转密钥)
### 日志监控
- [ ] 记录访问日志
- [ ] 监控异常请求
- [ ] 配置 fail2ban
---
## 13. 安全测试工具
### 在线测试
- SSL Labs: https://www.ssllabs.com/ssltest/
- Security Headers: https://securityheaders.com/
- Observatory: https://observatory.mozilla.org/
### 命令行工具
```bash
# SSL 测试
testssl.sh example.com
# 头部检查
curl -I https://example.com
# 漏洞扫描
nikto -h https://example.com
nmap --script http-vuln* -p 443 example.com
```