服务安全详解#
Nginx 作为全球使用最广泛的 Web 服务器之一,承载着无数网站和应用的流量入口。然而,默认配置往往存在安全隐患。本文将结合实际生产环境经验,系统性地讲解 Nginx 安全加固的各个维度,帮助读者构建一个安全可靠的 Web 服务。
⚠️ 声明:本文所有配置示例均为通用模板,请根据实际环境调整,切勿直接照搬。
一、基础安全配置#
1.1 以非特权用户运行#
Nginx master 进程以 root 启动,但 worker 进程应使用普通用户:
# 使用专用用户运行 worker 进程
user nginx nginx;
# 或者使用 www-data
user www-data www-data;即使 worker 进程被攻破,攻击者也仅有普通用户权限,无法控制系统核心。
1.2 隐藏版本信息#
暴露具体版本号会给攻击者提供定向攻击的依据:
# 关闭版本号显示
server_tokens off;
# 同时在编译时可以修改版本标识
# ./configure --with-cc-opt='-DNGX_HTTP_SERVER_STRING="Server: Custom"'1.3 限制进程打开文件数#
# 单个 worker 进程最大打开文件数
worker_rlimit_nofile 65535;二、访问控制与请求限制#
2.1 限制请求方法和大小#
# 只允许常见的 HTTP 方法
if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE)$) {
return 405;
}
# 限制请求体大小(防止大文件上传攻击)
client_max_body_size 10M;
# 限制请求头缓冲区
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;2.2 速率限制#
防止暴力破解和 CC 攻击的核心配置:
# 定义限流区域(http 块中)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# 应用限流(server 或 location 块中)
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
proxy_pass http://backend;
}
# 针对登录接口更严格的限制
location /login {
limit_req zone=api_limit burst=5 nodelay;
# 额外增加延迟验证
auth_request /auth;
}参数说明:
| 参数 | 说明 |
|---|---|
rate=10r/s |
每秒允许 10 个请求 |
burst=20 |
允许突发 20 个请求排队 |
nodelay |
突发请求立即处理,否则会延迟 |
2.3 连接数限制#
# 限制同一 IP 的并发连接数
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 10;
# 限制同一虚拟服务器的总连接数
limit_conn_zone $server_name zone=perserver:10m;
limit_conn perserver 1000;三、敏感路径与文件保护#
3.1 禁止访问隐藏文件#
# 禁止所有以点开头的文件/目录(.git, .env, .htaccess 等)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}3.2 保护敏感文件类型#
# 禁止访问备份、配置、日志等文件
location ~* \.(bak|config|sql|log|sh|inc|swp|old|save|orig|tmp)$ {
deny all;
return 404;
}
# 保护系统文件
location ~* (composer\.json|composer\.lock|package\.json|package-lock\.json|Dockerfile|\.env) {
deny all;
return 404;
}3.3 限制目录列表#
# 禁止自动列出目录内容
autoindex off;
# 针对特定目录可开启(如文件下载站)
location /downloads/ {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}3.4 防止图片盗链#
location ~* \.(jpg|jpeg|png|gif|webp)$ {
valid_referers none blocked *.example.com example.com;
if ($invalid_referer) {
return 403;
# 或者返回防盗链图片
# rewrite ^/.*$ /images/hotlink.jpg break;
}
}四、HTTPS 与 SSL/TLS#
4.1 强制 HTTPS 跳转#
# HTTP 强制跳转 HTTPS
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}4.2 现代 SSL/TLS 配置#
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# 证书配置
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/private.key;
# 只启用 TLS 1.2 和 1.3
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';
# 优先使用服务器端密码顺序
ssl_prefer_server_ciphers on;
# Session 缓存
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling(加快证书验证)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
# DNS 解析器(用于 OCSP)
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
}4.3 HSTS 配置(可选)#
# 严格传输安全(分阶段启用)
# 阶段1:测试期(5分钟)
add_header Strict-Transport-Security "max-age=300" always;
# 阶段2:短期(1天)
add_header Strict-Transport-Security "max-age=86400" always;
# 阶段3:正式期(1年,包含子域名)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;⚠️ 重要提示:启用
preload前请确保:
- 所有子域名均支持 HTTPS
- 证书长期有效且不会间断
- 确定永远不会回退到 HTTP
五、安全响应头#
这是经常被忽视但极其重要的安全层:
server {
# 防止点击劫持
add_header X-Frame-Options "SAMEORIGIN" always;
# 启用 XSS 过滤器
add_header X-XSS-Protection "1; mode=block" always;
# 防止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" 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'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:" always;
# 跨域资源策略
add_header Cross-Origin-Resource-Policy "same-origin" always;
# 跨域嵌入策略
add_header Cross-Origin-Embedder-Policy "require-corp" always;
# 跨域打开策略
add_header Cross-Origin-Opener-Policy "same-origin" always;
}六、日志监控#
6.1 合理的日志配置#
# 自定义日志格式(包含更多安全相关信息)
log_format security '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time '
'$ssl_protocol $ssl_cipher '
'"$http_x_forwarded_for"';
# 访问日志
access_log /var/log/nginx/access.log security buffer=32k flush=5s;
# 错误日志级别:warn(记录警告及以上)
error_log /var/log/nginx/error.log warn;6.2 异常请求监控#
# 记录 404 请求(用于发现扫描行为)
location / {
# ... 正常配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
# 单独记录攻击尝试
map $status $log_4xx {
~^4 1;
default 0;
}
access_log /var/log/nginx/attack.log combined if=$log_4xx;6.3 日志分析#
#!/bin/bash
# 分析扫描行为
# 查找可疑的 404 扫描
echo "=== 可疑扫描 IP TOP10 ==="
grep " 404 " /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# 查找暴力破解尝试
echo "=== 登录接口请求 TOP10 ==="
grep "POST /login" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# 查找 SQL 注入尝试
echo "=== SQL 注入特征请求 ==="
grep -i "select\|union\|insert\|drop\|--\|#" /var/log/nginx/access.log七、防御常见攻击#
7.1 防止 SQL 注入(WAF 级规则)#
# 基础 SQL 注入过滤规则
set $block_sql_inject 0;
if ($query_string ~* "(\bselect\b.*\bfrom\b|\bunion\b.*\bselect\b|information_schema|benchmark\()") {
set $block_sql_inject 1;
}
if ($block_sql_inject = 1) {
return 403;
}7.2 防止路径遍历#
# 禁止目录遍历
location ~* \.(\.|%2e|%2E){2}(/|%2f|%2F) {
deny all;
return 404;
}
# 规范化 URI
location ~* (\.\./|\.\.\\) {
deny all;
}7.3 防止 User-Agent 扫描#
# 拦截常见扫描工具
if ($http_user_agent ~* (nikto|sqlmap|nessus|nmap|acunetix|wpscan|dirbuster|gobuster)) {
return 444; # Nginx 特殊状态码,直接断开连接
}7.4 慢速攻击防护#
# 设置客户端请求超时
client_body_timeout 10s; # 读取请求体超时
client_header_timeout 10s; # 读取请求头超时
send_timeout 10s; # 发送响应超时
# 限制请求体大小(防大包攻击)
client_max_body_size 1M;八、代理安全#
Nginx 反向代理#
location /api/ {
proxy_pass http://backend;
# 传递真实客户端 IP
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_hide_header X-Powered-By;
proxy_hide_header Server;
# 限制代理超时(防慢连接)
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
# 缓冲响应(防内存溢出)
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}九、监控告警#
9.1 关键指标#
#!/bin/bash
# Nginx 安全监控脚本
# 监控异常状态码比例
TOTAL=$(tail -10000 /var/log/nginx/access.log | wc -l)
ERRORS=$(tail -10000 /var/log/nginx/access.log | grep -E " 40[0-9]| 50[0-9]" | wc -l)
ERROR_RATE=$((ERRORS * 100 / TOTAL))
if [ $ERROR_RATE -gt 20 ]; then
echo "警告:错误率过高 ${ERROR_RATE}%"
# 发送告警
fi
# 监控单个 IP 请求频率
tail -10000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | awk '$1 > 200 {print "可疑 IP: "$2" 请求数:"$1}'9.2 自动化封禁#
#!/bin/bash
# 自动封禁攻击 IP
# 封禁 5 分钟内请求超过 100 次的 IP
tail -5000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | awk '$1 > 100 {print $2}' | while read IP; do
iptables -I INPUT -s $IP -j DROP
echo "$(date): Banned $IP" >> /var/log/nginx/ban.log
done总结#
Nginx 安全加固是一个持续的过程,而非一次性的配置。随着攻击技术的演进和业务需求的变化,安全策略也需要不断调整和优化。
核心原则#
| 原则 | 说明 |
|---|---|
| 最小权限 | 只开放必要的端口和功能 |
| 纵深防御 | 不要依赖单一安全措施 |
| 持续监控 | 日志是最好的安全传感器 |
| 定期评估 | 定期检查和更新安全配置 |
🛡️ 记住:没有绝对的安全,只有相对的安全。重要的是建立及时发现、快速响应、持续改进的安全机制。