Nginx作为高性能的HTTP和反向代理服务器 广泛应用于生产环境 但默认配置存在诸多安全隐患 易遭受SQL注入 XSS CSRF DDoS等攻击 同时 HTTP协议传输数据明文可见 存在数据泄露风险
核心目标:通过配置加固提升Nginx抗攻击能力 通过HTTPS实现数据加密传输 符合生产环境安全规范
Nginx安全防护实战配置
安全防护核心思路:最小权限原则 禁用不必要功能 拦截恶意请求 隐藏敏感信息 限制请求频率
隐藏Nginx版本信息
默认情况下,Nginx响应头会暴露版本号及操作系统信息 攻击者可利用版本漏洞针对性攻击 需隐藏版本信息并自定义服务器标识
配置步骤:
-
编辑Nginx主配置文件(通常路径:/etc/nginx/nginx.conf)
-
在http块中添加以下配置: # 隐藏版本号
server_tokens off;# 自定义服务器响应头标识(避免暴露Nginx)server_tag "Web Server";# 隐藏X-Powered-By头(若后端有PHP等服务 需同步配置)``add_header X-Powered-By "Custom Server" always -
重启Nginx生效:systemctl restart nginx
-
验证:使用curl -I 域名 查看响应头中无Server: nginx/版本号 且X-Powered-By为自定义内容
限制请求频率(防御DDoS/CC攻击)
通过limit_req模块限制单个IP的请求频率 防止恶意请求占用服务器资源 需先确保Nginx编译时启用了limit_req模块(默认启用)
配置步骤:
-
在http块中定义请求限制规则(全局生效):
# 定义请求频率限制池(name=req_limit,容量10,每秒允许2个请求,超出放入队列等待) ``limit_req_zone $binary_remote_addr zone=req_limit:10m rate=2r/s; ``# 限制单个IP的并发连接数(全局限制,可根据业务调整) ``limit_conn_zone $binary_remote_addr zone=conn_limit:10m; ``limit_conn conn_limit 10 -
在server块或location块中应用限制规则(针对具体站点/接口):
server { `` listen 80; `` server_name example.com; `` # 应用请求频率限制,burst=5表示队列容量5,nodelay表示超出后直接返回503,不等待 `` limit_req zone=req_limit burst=5 nodelay; `` # 限制并发连接数(局部可覆盖全局) `` limit_conn conn_limit 8; `` ... ``} -
重启Nginx 验证 使用ab工具压测(ab -n 100 -c 10 域名) 超出频率后会返回503状态码
拦截恶意请求(防御SQL注入、XSS)
通过location匹配规则 拦截包含恶意字符(如SQL注入语句 XSS脚本)的请求 直接返回403禁止访问
配置步骤(在server块中添加)
# 拦截SQL注入相关字符
location ~* (union|select|insert|update|delete|drop|alter|truncate|exec) {
return 403 "Forbidden: Malicious Request";
}
# 拦截XSS相关脚本字符
location ~* (<|>|script|javascript|alert|eval) {
return 403 "Forbidden: Malicious Script";
}
# 禁止访问敏感文件(如.git、.env、配置文件)
location ~* (\.git|\_env|.conf|.log) {
deny all;
return 403;
}
# 限制请求方法(只允许GET、POST,禁止PUT、DELETE等)
if ($request_method !~ ^(GET|POST)$) {
return 405;
}
配置安全响应头(增强浏览器安全)
通过add_header配置安全相关响应头 防止XSS 点击劫持等攻击 提升浏览器层面的安全性 配置在http块或server块中
# 防止XSS攻击:禁止页面加载未授权脚本
add_header X-XSS-Protection "1; mode=block" always;
# 防止点击劫持:禁止页面被嵌入iframe
add_header X-Frame-Options "SAMEORIGIN" always;
# 限制资源加载:只允许同源资源(可根据业务调整为具体域名)
add_header Content-Security-Policy "default-src 'self'" always;
# 强制HTTPS:告知浏览器后续请求优先使用HTTPS(配合HTTPS部署)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 禁止泄露Referer信息(可选,根据业务需求)
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# 禁止浏览器自动解析MIME类型(防止恶意文件伪装)
add_header X-Content-Type-Options "nosniff" always;
最小权限配置(降低服务器风险)
-
修改Nginx运行用户:默认使用root用户 风险较高 需创建专用低权限用户(如nginx)在nginx.conf的user指令中修改:
user nginx nginx; # 用户名 组名 -
修改网站目录权限:网站根目录(如/usr/share/nginx/html)权限设置为755 文件权限设置为644 禁止777权限:
chown -R nginx:nginx /usr/share/nginx/html ``chmod -R 755 /usr/share/nginx/html ``chmod -R 644 /usr/share/nginx/html/* -
禁用不必要的模块:编辑nginx.conf 注释掉不需要的模块(如autoindex自动索引模块)减少攻击面:
# autoindex on; # 注释掉自动索引 避免暴露目录结构
HTTPS部署实战(Let's Encrypt免费证书)
HTTPS基于SSL/TLS协议 实现数据传输加密 需先获取SSL证书(推荐Let's Encrypt免费证书 有效期3个月 可自动续期) 部署流程分为:安装Certbot工具 获取证书 配置Nginx HTTPS 设置自动续期
环境准备
-
确保服务器已开放80、443端口(防火墙配置):
# 开放80、443端口 ``firewall-cmd --permanent --add-port=80/tcp ``firewall-cmd --permanent --add-port=443/tcp ``# 重新加载防火墙 ``firewall-cmd --reload -
确保域名已解析到当前服务器IP(公网环境 内网可使用自签名证书)
安装Certbot工具(获取免费证书)
-
安装EPEL源(CentOS系统):
yum install epel-release -y -
安装Certbot及Nginx插件:
yum install certbot python3-certbot-nginx -y
获取Let's Encrypt证书
bash
certbot --nginx -d example.com -d www.example.com
-
执行命令后,输入邮箱(用于证书到期提醒)同意服务条款 选择是否开启HTTPS重定向(推荐选择2 自动将HTTP请求重定向到HTTPS)
-
执行成功后 证书会自动保存到/etc/letsencrypt/live/example.com/目录下 包含以下文件
-
fullchain.pem:完整证书链(包含服务器证书和根证书)
-
privkey.pem:服务器私钥(请勿泄露)
-
cert.pem:服务器证书
-
chain.pem:根证书链
-
手动优化HTTPS配置(可选,增强安全性)
bash
server {
listen 443 ssl http2; # 启用HTTP/2,提升传输效率
server_name example.com www.example.com;
# SSL证书配置
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 优化SSL协议(禁用不安全的SSLv2、SSLv3、TLSv1、TLSv1.1)
ssl_protocols TLSv1.2 TLSv1.3;
# 优化加密套件(优先使用安全的加密算法)
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
# 启用会话复用,提升性能
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 启用OCSP stapling,提升证书验证速度
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# 安全响应头(可沿用之前的配置)
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 网站根目录及默认页面
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
}
# HTTP请求重定向到HTTPS(Certbot自动生成,可优化)
server {
listen 80;
server_name example.com www.example.com;
# 永久重定向,告知浏览器后续优先使用HTTPS
return 301 https://$host$request_uri;
}
设置证书自动续期
Let's Encrypt证书有效期为90天 需设置自动续期 避免证书过期导致服务不可用 通过crontab设置定时任务
-
执行以下命令 添加定时任务:
crontab -e -
添加以下内容(每天凌晨2点自动续期,续期成功后重启Nginx):
0 2 * * * certbot renew --quiet --renew-hook "systemctl restart nginx" -
验证定时任务:crontab -l 查看是否添加成功
--quiet表示静默续期 不输出日志 --renew-hook表示续期成功后执行的命令(重启Nginx使证书生效)
HTTPS验证
-
重启Nginx:systemctl restart nginx
-
浏览器访问https://example.com 查看地址栏是否有"小锁"图标 点击可查看证书信息
-
使用在线工具(如SSL Labs)检测HTTPS安全性 保评分达到A+
常见问题排查
Nginx重启失败
-
问题原因:配置文件语法错误 端口被占用 权限不足
-
排查方法:
# 检查配置文件语法 ``nginx -t ``# 查看端口占用情况(80/443) ``netstat -tulnp | grep 80 ``netstat -tulnp | grep 443 ``# 查看Nginx日志(错误日志路径通常为/var/log/nginx/error.log) ``tail -f /var/log/nginx/error.log
HTTPS访问失败(提示证书无效)
-
问题原因:证书路径配置错误 私钥与证书不匹配 域名与证书绑定不一致
-
排查方法:
-
检查证书路径是否正确(fullchain.pem和privkey.pem的路径)
-
验证私钥与证书是否匹配:
openssl rsa -noout -modulus -in /etc/letsencrypt/live/example.com/privkey.pem | openssl md5 ``openssl x509 -noout -modulus -in /etc/letsencrypt/live/example.com/cert.pem | openssl md5两次输出的md5值需一致 否则私钥与证书不匹配 -
检查域名是否与证书绑定(Certbot获取证书时指定的域名需与访问域名一致)
-
安全防护配置后误拦正常请求
-
问题原因:正则匹配规则过于严格 拦截了正常业务请求
-
排查方法:查看Nginx访问日志(/var/log/nginx/access.log)找到返回403的请求 分析请求路径和参数 调整正则规则(如添加例外情况)