# NGINX 安全深度指南 ## 目录 1. [Bot 检测与防护](#1-bot-检测与防护) 2. [WAF 配置深度指南(ModSecurity)](#2-waf-配置深度指南modsecurity) 3. [DDoS 防护策略](#3-ddos-防护策略) 4. [OWASP Top 10 防护](#4-owasp-top-10-防护) 5. [安全响应头完整配置](#5-安全响应头完整配置) 6. [CVE 历史漏洞与修复版本](#6-cve-历史漏洞与修复版本) 7. [安全审计日志配置](#7-安全审计日志配置) 8. [完整安全配置示例](#8-完整安全配置示例) --- ## 1. Bot 检测与防护 ### 1.1 基于 User-Agent 的 Bot 识别 ```nginx map $http_user_agent $bot_type { default "human"; # 善意爬虫(白名单) ~*googlebot "good_bot"; ~*bingbot "good_bot"; ~*duckduckbot "good_bot"; ~*baiduspider "good_bot"; ~*yandexbot "good_bot"; ~*facebookexternalhit "good_bot"; ~*twitterbot "good_bot"; ~*linkedinbot "good_bot"; ~*whatsapp "good_bot"; # 恶意爬虫/扫描器 ~*sqlmap "bad_bot"; ~*nikto "bad_bot"; ~*masscan "bad_bot"; ~*zgrab "bad_bot"; ~*nmap "bad_bot"; ~*nessus "bad_bot"; ~*burp "bad_bot"; ~*gobuster "bad_bot"; ~*dirbuster "bad_bot"; ~*wfuzz "bad_bot"; ~*crawler4j "bad_bot"; ~*scrapy "bad_bot"; ~*python-requests "bad_bot"; # 自动化工具 ~*curl "tool"; ~*wget "tool"; ~*python-urllib "tool"; ~*java "tool"; ~*libwww-perl "tool"; ~*httpclient "tool"; } # 基于行为的检测 map $http_user_agent $suspicious_behavior { default 0; ~*bot 1; ~*spider 1; ~*crawl 1; ~*scan 1; ~*probe 1; } ``` ### 1.2 验证爬虫真实性 ```nginx server { listen 80; server_name example.com; # 白名单爬虫验证(反向 DNS 验证) location / { # 仅对白名单爬虫进行验证 if ($bot_type = "good_bot") { # 验证 Googlebot if ($http_user_agent ~* googlebot) { # 实际生产环境需使用 Lua/NJS 进行反向 DNS 验证 # 此处仅示例 access_log /var/log/nginx/verified_bots.log; } } # 拦截恶意爬虫 if ($bot_type = "bad_bot") { return 444; # 无响应断开连接 } # 限制自动化工具 if ($bot_type = "tool") { limit_req zone=tool_limit burst=1 nodelay; } proxy_pass http://backend; } } ``` ### 1.3 基于行为的 Bot 检测 ```nginx # 定义 Bot 检测区域 limit_req_zone $binary_remote_addr zone=bot_detect:10m rate=1r/s; server { # 无 User-Agent 检测 if ($http_user_agent = "") { return 403; } # 高频请求检测 location / { # 检查请求频率异常 limit_req zone=bot_detect burst=5 nodelay; # 检测无 referer 的 POST 请求(常见于 CSRF/Bot) if ($request_method = POST) { set $post_check 1; } if ($http_referer = "") { set $post_check "${post_check}1"; } if ($post_check = "11") { return 403 "Suspicious request detected"; } # 检测异常 header 组合 if ($http_accept = "") { return 403; } proxy_pass http://backend; } } ``` ### 1.4 挑战-响应机制(使用 Lua) ```nginx # 需要 ngx_http_lua_module server { location / { access_by_lua_block { local bot_type = ngx.var.bot_type if bot_type == "suspicious" then -- 发送 JavaScript 挑战 ngx.header.content_type = "text/html" ngx.say([[ ]]) ngx.exit(ngx.HTTP_OK) end -- 验证 cookie local cookies = ngx.var.http_cookie if not cookies or not cookies:match("js_enabled=1") then ngx.exit(ngx.HTTP_FORBIDDEN) end } proxy_pass http://backend; } } ``` ### 1.5 Bot 管理策略表 | 类别 | 特征 | 处理方式 | |------|------|----------| | **善意爬虫** | Google/Bing/Baidu 等搜索引擎 | 验证真实性后放行,设置独立 rate limit | | **监控 Bot** | Uptime 检查、SEO 工具 | IP 白名单,设置宽松的限制 | | **恶意爬虫** | 扫描器、暴力破解工具 | 立即阻断,记录日志 | | **自动化工具** | curl/wget/脚本 | 严格限制频率,验证码挑战 | | **未知 Bot** | 未识别的 User-Agent | 行为分析,可疑则挑战验证 | --- ## 2. WAF 配置深度指南(ModSecurity) ### 2.1 ModSecurity 编译安装 ```bash # 安装依赖 apt-get install -y libpcre3-dev libxml2-dev libcurl4-openssl-dev \ liblua5.3-dev libssl-dev libyajl-dev # 下载 ModSecurity v3 cd /usr/src git clone --depth 1 -b v3/master https://github.com/SpiderLabs/ModSecurity cd ModSecurity git submodule init git submodule update # 编译安装 ./build.sh ./configure --with-yajl --with-ssdeep --with-lua --with-maxmind make -j$(nproc) make install # 下载 NGINX 连接器 cd /usr/src git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx # 编译 NGINX 模块(需 NGINX 源码) cd /usr/src/nginx-1.24.0 ./configure --add-module=/usr/src/ModSecurity-nginx [其他配置选项] make modules ``` ### 2.2 核心配置 ```nginx # modsecurity.conf - 主配置文件 load_module modules/ngx_http_modsecurity_module.so; http { # 全局 ModSecurity 配置 modsecurity on; modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf; server { listen 80; server_name example.com; location / { # 可为特定 location 启用/禁用 modsecurity on; # 内联规则 modsecurity_rules ' SecRuleEngine On SecRule REQUEST_URI "@contains /admin" \ "id:1000,phase:1,deny,status:403,msg:'Admin access restricted'" '; proxy_pass http://backend; } # 静态资源跳过 WAF location ~* \\.(jpg|jpeg|png|gif|css|js|woff|woff2)$ { modsecurity off; proxy_pass http://backend; } } } ``` ### 2.3 ModSecurity 核心规则集(CRS) ```ini # /etc/nginx/modsecurity/crs-setup.conf # 规则引擎模式 SecRuleEngine DetectionOnly # 仅检测模式(测试阶段) # SecRuleEngine On # 阻断模式(生产环境) # 异常评分阈值 SecAction "id:900001,phase:1,nolog,pass,t:none,setvar:tx.inbound_anomaly_score_threshold=5" SecAction "id:900002,phase:1,nolog,pass,t:none,setvar:tx.outbound_anomaly_score_threshold=4" # 检测 Paranoia Level(0-4,越高越严格) SecAction "id:900003,phase:1,nolog,pass,t:none,setvar:tx.paranoia_level=2" # 允许特定路径(排除规则) SecRule REQUEST_URI "@beginsWith /api/webhook" \ "id:1001,phase:1,pass,nolog,ctl:ruleEngine=Off" # 自定义白名单 SecRule REQUEST_HEADERS:User-Agent "@contains MyInternalApp" \ "id:1002,phase:1,pass,nolog,ctl:ruleRemoveById=913100" # 自定义规则 - SQL 注入增强 SecRule REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* \ "@rx (?i:(?:select\\s*\\*\\s*from|union\\s*select.*from|insert\\s+into|delete\\s+from|drop\\s+table))" \ "id:1003,phase:2,deny,status:403,msg:'SQL Injection Detected',logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}'" ``` ### 2.4 规则集加载配置 ```nginx # 在 nginx.conf 中加载 CRS modsecurity_rules_file /etc/nginx/modsecurity/crs-setup.conf; modsecurity_rules ' # 加载 CRS 规则 Include /usr/share/modsecurity-crs/crs-setup.conf Include /usr/share/modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf Include /usr/share/modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf Include /usr/share/modsecurity-crs/rules/REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf Include /usr/share/modsecurity-crs/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf Include /usr/share/modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf Include /usr/share/modsecurity-crs/rules/REQUEST-910-IP-REPUTATION.conf Include /usr/share/modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf Include /usr/share/modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf Include /usr/share/modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf Include /usr/share/modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf Include /usr/share/modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf Include /usr/share/modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf Include /usr/share/modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf Include /usr/share/modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf Include /usr/share/modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf Include /usr/share/modsecurity-crs/rules/REQUEST-934-APPLICATION-ATTACK-GENERIC.conf Include /usr/share/modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf Include /usr/share/modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf Include /usr/share/modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf Include /usr/share/modsecurity-crs/rules/REQUEST-944-APPLICATION-ATTACK-JAVA.conf Include /usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf Include /usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf Include /usr/share/modsecurity-crs/rules/REQUEST-999-EXCLUSION-RULES-AFTER-CRS.conf '; ``` ### 2.5 虚拟补丁配置 ```ini # /etc/nginx/modsecurity/virtual-patches.conf # CVE-2021-44228 (Log4j) SecRule REQUEST_HEADERS|REQUEST_HEADERS_NAMES|REQUEST_BODY|ARGS|ARGS_NAMES \ "@rx \\$\\{.*jndi:(ldap|ldaps|dns|rmi|iiop|http|https|corba|nis|nds)" \ "id:2001,phase:2,deny,status:403,msg:'CVE-2021-44228 Log4j RCE attempt',logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}'" # CVE-2017-9805 (Struts REST XStream) SecRule REQUEST_HEADERS:Content-Type "@contains application/x-www-form-urlencoded" \ "id:2002,phase:1,deny,status:403,msg:'CVE-2017-9805 Struts REST XStream',chain" SecRule REQUEST_BODY "@contains &1 | grep -oP 'nginx/\\K[0-9.]+') LATEST=$(curl -s https://nginx.org/en/download.html | grep -oP 'Stable version.*?nginx-[0-9.]+' | grep -oP '[0-9.]+$' | head -1) if [ "$CURRENT" != "$LATEST" ]; then echo "警告: NGINX 版本 $CURRENT 需要更新到 $LATEST" # 发送通知... fi ``` ### 6.3 安全更新流程 ```bash # 1. 备份当前配置 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup.$(date +%Y%m%d) tar -czf /backup/nginx-config-$(date +%Y%m%d).tar.gz /etc/nginx/ # 2. 测试新配置 nginx -t # 3. 平滑升级(热升级) # 下载并编译新版本 make upgrade # 或使用包管理器 apt-get update && apt-get install --only-upgrade nginx # 4. 验证升级 nginx -v systemctl status nginx # 5. 回滚准备(保留旧二进制) mv /usr/sbin/nginx /usr/sbin/nginx.old ``` --- ## 7. 安全审计日志配置 ### 7.1 安全审计日志格式 ```nginx # /etc/nginx/conf.d/audit-log.conf # 安全审计专用日志格式 log_format security '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time" ' 'ssl_protocol=$ssl_protocol ssl_cipher=$ssl_cipher ' 'req_id=$request_id ' 'xff=$http_x_forwarded_for ' 'real_ip=$http_x_real_ip ' 'cc=$geoip_country_code ' 'city=$geoip_city '; # 攻击检测日志格式 log_format attack '$time_iso8601|$remote_addr|$request_method|$request_uri|' '$status|$http_user_agent|$http_referer|' '$request_time|$upstream_response_time|' '$http_x_forwarded_for|$geoip_country_code|' '$connection_requests|$msec'; # 安全事件日志 log_format security_event 'time=$time_iso8601 ' 'client=$remote_addr ' 'method=$request_method ' 'uri="$request_uri" ' 'status=$status ' 'request_length=$request_length ' 'body_bytes_sent=$body_bytes_sent ' 'referer="$http_referer" ' 'user_agent="$http_user_agent" ' 'cookie=$http_cookie ' 'authorization=$http_authorization ' 'content_type=$content_type ' 'content_length=$content_length ' 'host=$host ' 'server_name=$server_name ' 'request_id=$request_id ' 'ssl_session_id=$ssl_session_id ' 'ssl_session_reused=$ssl_session_reused'; ``` ### 7.2 条件日志记录 ```nginx http { # 仅记录特定状态码 map $status $loggable { ~^[23] 0; # 2xx/3xx 不记录 default 1; # 其他记录 } # 仅记录慢请求 map $request_time $slow_request { ~^[0-2]\\. 0; # < 3s 不记录 default 1; # >= 3s 记录 } # 合并条件 map "${loggable}${slow_request}" $security_log { "00" 0; default 1; } server { access_log /var/log/nginx/security.log security if=$security_log; location / { proxy_pass http://backend; } } } ``` ### 7.3 安全事件过滤 ```nginx # 记录特定安全事件 map "$status:$request_method:$http_user_agent" $security_event { default 0; # 记录所有 401/403 "~^401" 1; "~^403" 1; "~^404" 1; # 记录攻击特征 "~*sqlmap" 1; "~*nikto" 1; "~*nmap" 1; # 记录 POST 到敏感路径 "~*:POST:.*/(admin|config|setup|install|phpmyadmin)" 1; } server { access_log /var/log/nginx/security-events.log attack if=$security_event; # 错误日志分离 error_log /var/log/nginx/security-error.log warn; } ``` ### 7.4 日志轮转与保留 ```bash # /etc/logrotate.d/nginx-security /var/log/nginx/security*.log { daily missingok rotate 90 compress delaycompress notifempty create 0640 www-data adm sharedscripts postrotate if [ -f /var/run/nginx.pid ]; then kill -USR1 $(cat /var/run/nginx.pid) fi endscript } # 攻击日志长期保留 /var/log/nginx/attack*.log { weekly missingok rotate 520 # 保留 10 年 compress delaycompress create 0640 www-data adm sharedscripts postrotate kill -USR1 $(cat /var/run/nginx.pid) endscript } ``` ### 7.5 实时安全监控脚本 ```bash #!/bin/bash # /usr/local/bin/nginx-security-monitor.sh LOG_FILE="/var/log/nginx/security.log" ALERT_THRESHOLD=100 # 每分钟请求数阈值 BLOCK_THRESHOLD=10 # 触发封禁的异常请求数 # 实时监控 tail -F $LOG_FILE | while read line; do # 提取 IP ip=$(echo "$line" | awk '{print $1}') # 检查攻击模式 if echo "$line" | grep -qE "(union|select|script|alert|eval\\(|system\\()"; then echo "$(date): SQL/XSS 攻击检测: $ip - $line" >> /var/log/nginx/alerts.log # 可选:自动添加到黑名单 # echo "deny $ip;" >> /etc/nginx/conf.d/auto-block.conf fi # 检查扫描行为 if echo "$line" | grep -qE "(\\.env|\\.git|config\\.xml|phpmyadmin|wp-admin)"; then echo "$(date): 敏感路径扫描: $ip - $line" >> /var/log/nginx/alerts.log fi done ``` --- ## 8. 完整安全配置示例 ### 8.1 生产环境安全配置 ```nginx # /etc/nginx/nginx.conf - 安全强化主配置 user nginx; worker_processes auto; worker_rlimit_nofile 65535; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; # 加载动态模块 load_module modules/ngx_http_geoip_module.so; load_module modules/ngx_http_modsecurity_module.so; events { worker_connections 4096; use epoll; multi_accept on; } http { # 基础设置 include /etc/nginx/mime.types; default_type application/octet-stream; # 隐藏版本号 server_tokens off; # 字符编码 charset utf-8; # 日志格式 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time"'; log_format security '$remote_addr - $time_iso8601 - "$request" - $status - ' '"$http_user_agent" - "$http_referer" - ' 'req_time=$request_time - xff="$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; # 性能优化 sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # Gzip 压缩 gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; # 客户端限制 client_max_body_size 10m; client_body_buffer_size 128k; client_header_buffer_size 1k; large_client_header_buffers 4 8k; client_body_timeout 12s; client_header_timeout 12s; # 缓冲区设置 proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; # GeoIP geoip_country /usr/share/GeoIP/GeoIP.dat; geoip_city /usr/share/GeoIP/GeoLiteCity.dat; # 限流区域 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=api_limit:10m rate=50r/s; limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/m; limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # Bot 检测 map $http_user_agent $bot_type { default "human"; ~*googlebot "good_bot"; ~*bingbot "good_bot"; ~*sqlmap "bad_bot"; ~*nikto "bad_bot"; ~*nmap "bad_bot"; ~*curl "tool"; ~*wget "tool"; } # 国家代码映射 map $geoip_country_code $allowed_country { default yes; CN yes; US yes; JP yes; RU no; KP no; IR no; } # 包含其他配置 include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } ``` ### 8.2 HTTPS 站点安全配置 ```nginx # /etc/nginx/sites-available/example.com server { listen 80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; # SSL 证书 ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; # SSL 配置 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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_dhparam /etc/nginx/ssl/dhparam.pem; # SSL 会话 ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/nginx/ssl/example.com.chain.crt; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; # 安全响应头 add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:; connect-src 'self' https://api.example.com; frame-ancestors 'self'; form-action 'self'; base-uri 'self';" always; add_header Cross-Origin-Embedder-Policy "require-corp" always; add_header Cross-Origin-Opener-Policy "same-origin" always; add_header Cross-Origin-Resource-Policy "same-origin" always; # 根目录 root /var/www/example.com; index index.html index.htm; # 日志 access_log /var/log/nginx/example.com-access.log main; error_log /var/log/nginx/example.com-error.log warn; # 全局限制 limit_conn conn_limit 20; limit_req zone=req_limit burst=20 nodelay; # 安全过滤 if ($bad_ip) { return 444; } if ($allowed_country = no) { return 403; } # 敏感文件保护 location ~ /\\. { deny all; return 404; } location ~* \\.(git|svn|env|config|log|sql|backup|bak|swp|old|orig|save)$ { deny all; return 404; } # 静态资源 location ~* \\.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|eot|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; add_header X-Frame-Options "SAMEORIGIN" always; access_log off; } # API 路由 location /api/ { limit_req zone=api_limit burst=50 nodelay; # 内容类型验证 if ($content_type !~ ^(application/json|application/x-www-form-urlencoded|multipart/form-data)$) { return 415; } # 方法限制 if ($request_method !~ ^(GET|POST|PUT|DELETE|PATCH|OPTIONS)$) { return 405; } # CORS if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://example.com" always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always; add_header Access-Control-Allow-Credentials "true" always; add_header Access-Control-Max-Age 86400 always; return 204; } add_header Access-Control-Allow-Origin "https://example.com" always; add_header Access-Control-Allow-Credentials "true" always; proxy_pass http://api_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id; } # 认证路由 location /auth/ { limit_req zone=login_limit burst=3 nodelay; proxy_pass http://auth_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 主应用 location / { try_files $uri $uri/ /index.html; # 安全响应头(静态页面) add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; } } ``` ### 8.3 WAF 完整配置 ```nginx # /etc/nginx/conf.d/waf.conf # ModSecurity 全局配置 modsecurity on; modsecurity_rules_file /etc/nginx/modsecurity/main.conf; # 特定路径规则 server { location / { # 启用完整 CRS modsecurity_rules ' SecRuleEngine On SecRequestBodyAccess On SecResponseBodyAccess On SecResponseBodyLimit 524288 SecResponseBodyLimitAction ProcessPartial # 文件上传限制 SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072 # 允许文件上传类型 SecRule REQUEST_FILENAME "@rx \\.(jpg|jpeg|png|gif|pdf|doc|docx)$" \ "id:2000,phase:1,pass,nolog,ctl:requestBodyLimit=52428800" # 加载 CRS Include /usr/share/modsecurity-crs/crs-setup.conf Include /usr/share/modsecurity-crs/rules/*.conf # 自定义排除 SecRule REQUEST_URI "@beginsWith /api/webhook" \ "id:9000,phase:1,pass,nolog,ctl:ruleRemoveById=920350" '; proxy_pass http://backend; } # 静态资源跳过 WAF location ~* \\.(jpg|jpeg|png|gif|css|js|woff|woff2|ttf|eot|svg|ico)$ { modsecurity off; expires 1y; access_log off; proxy_pass http://backend; } } ``` ### 8.4 安全配置检查清单 ```markdown ## 部署前检查清单 ### 基础安全 - [ ] 使用最新稳定版 NGINX - [ ] server_tokens 设置为 off - [ ] 禁用不安全的 SSL 协议(SSLv2/SSLv3/TLSv1.0/TLSv1.1) - [ ] 配置安全的加密套件 - [ ] 启用 HSTS - [ ] 配置所有安全响应头 ### 访问控制 - [ ] 管理后台 IP 白名单 - [ ] 敏感文件/目录访问限制 - [ ] 地理位置访问控制(如需要) - [ ] User-Agent 过滤 ### 请求限制 - [ ] 请求速率限制(通用) - [ ] API 专用限流 - [ ] 登录接口严格限流 - [ ] 连接数限制 - [ ] 带宽限制 ### WAF 防护 - [ ] ModSecurity 安装配置 - [ ] CRS 规则集加载 - [ ] 虚拟补丁规则 - [ ] 自定义业务规则 - [ ] 排除规则测试 ### 日志监控 - [ ] 安全审计日志配置 - [ ] 日志轮转设置 - [ ] 实时监控脚本 - [ ] fail2ban 集成 ### 性能与安全平衡 - [ ] 静态资源缓存策略 - [ ] 安全头对静态资源的影响 - [ ] WAF 对性能的损耗评估 - [ ] 限流阈值合理性测试 ### 测试验证 - [ ] SSL Labs A+ 评分 - [ ] Security Headers 检查 - [ ] OWASP ZAP 扫描 - [ ] 渗透测试 - [ ] 性能基准测试 ``` --- ## 附录:常用安全测试命令 ```bash # SSL/TLS 测试 openssl s_client -connect example.com:443 -tls1_2 openssl s_client -connect example.com:443 -tls1_3 testssl.sh example.com # 安全响应头检查 curl -I -s https://example.com | grep -E "^(Strict-Transport-Security|Content-Security-Policy|X-Frame-Options)" # 漏洞扫描基础 curl -s https://example.com/.env && echo "DANGER: .env exposed!" curl -s https://example.com/.git/HEAD && echo "DANGER: .git exposed!" curl -s https://example.com/config.xml && echo "DANGER: config exposed!" # 压力测试(限流验证) ab -n 1000 -c 100 https://example.com/api/test siege -c 50 -t 30s https://example.com/ ```