Nginx 静态站点安全加固实战
很多人觉得"静态站没什么好黑的"。实际不然——静态站点被黑最常见的形态是:
- 服务器层面失守(SSH 弱口令、旧版本漏洞)后整站被替换或挂黑链;
- Web 服务器配置不当:目录列表开着、
.git/目录裸奔、备份文件可下载; - HTTP 层缺防护:没有 HSTS 被运营商劫持插广告、没有 CSP 被注入脚本。
静态站没有 SQL 注入、没有反序列化,攻击面天然小,但上面这几条一条都不能少。以下是我给自己站(Nginx + 纯静态文件)做的加固清单,可直接抄。
1. 基础收敛
server_tokens off; # 隐藏 Nginx 版本号,别帮攻击者缩小漏洞范围
autoindex off; # 关闭目录列表(默认就是 off,显式写上防手贱)
2. 封禁敏感路径
部署时最容易留下的坑:.git/、编辑器备份文件、.env 之类。一刀切拒绝:
# deny dotfiles and backup leftovers
location ~ /\.(?!well-known) {
deny all;
return 404;
}
location ~* \.(bak|swp|sql|tar|gz|zip|log|sh)$ {
deny all;
return 404;
}
注意 /.well-known/ 要放行,acme.sh 签证书时 HTTP-01 验证要用。
3. 安全响应头
静态站的标准套装:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
逐条解释:
- nosniff:禁止浏览器 MIME 嗅探。没有它,一个上传目录里的文本文件可能被当脚本执行;
- X-Frame-Options:防点击劫持。纯内容站直接
DENY也行; - Referrer-Policy:外站只会拿到你的域名,拿不到完整路径(路径里可能有敏感参数);
- Permissions-Policy:明确禁用用不上的浏览器能力,纵深防御。
HTTPS 站再加 HSTS,强制浏览器后续只走 HTTPS:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
提醒:HSTS 一旦下发一年内无法撤销,上之前确认全站(含子域名)都能 HTTPS。
CSP 单独写了一篇:内容安全策略(CSP)从原理到落地。
4. 限流
静态站也会被扫描器和高频爬虫骚扰,给个宽松的全局限流即可:
limit_req_zone $binary_remote_addr zone=general:10m rate=20r/s;
server {
...
limit_req zone=general burst=40 nodelay;
}
正常用户不可能 1 秒打 20 个请求,这个阈值只拦机器。
5. TLS 配置(2026 版)
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 off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
TLS 1.0/1.1 已淘汰多年,不用留。证书用 acme.sh 免费续期即可。
6. 缓存与压缩
既是性能优化也是抗 DDoS 手段——能被浏览器缓存住的请求根本不落到后端:
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_min_length 1024;
location ~* \.(jpg|jpeg|png|gif|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public";
}
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public";
}
7. 文件与系统层
HTTP 层之外的三条底线:
# 站点根目录属主与 Nginx worker 分离,worker 只读
chown -R deploy:nginx /var/www/blog
chmod -R 750 /var/www/blog
# 上传/写入只给真正需要的目录
find /var/www/blog -type f -exec chmod 640 {} +
- Nginx worker 以低权限用户跑(默认 nobody/nginx,别手贱用 root);
- 站点目录对 worker 只读,发布走独立的部署用户 + rsync/git;
- 系统层:SSH 禁密码登录、fail2ban 兜底——多数"静态站被黑"其实是 SSH 被爆破。
验证
改完用 curl 逐条检查:
curl -sI https://www.example.com/ | grep -iE 'strict|x-content|x-frame|referrer|permissions'
curl -s -o /dev/null -w '%{http_code}\n' https://www.example.com/.git/HEAD
# 期望:404
再跑一轮 securityheaders.com 扫描,A 级才算过关。这份配置的完整版我放在本站仓库的 deploy/nginx-site.conf,和文章保持同步。