CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Nginx 反向代理入门/课时/安全响应头
RawBlame
课时目录12 节

Nginx 反向代理入门

  1. 01Nginx 是什么
  2. 02安装与 nginx -t
  3. 03配置文件结构
  4. 04静态资源
  5. 05反向代理基础
  6. 06双 upstream 架构
  7. 07HTTPS 与证书
  8. 08安全响应头
  9. 09缓存与性能
  10. 10负载均衡
  11. 11Nginx 与 Ingress
  12. 12综合练习

安全响应头

HSTS、CSP、X-Forwarded-* 与真实 IP。

25 分钟

安全响应头

这一课你将能做到

  1. 解释 HSTS、X-Content-Type-Options、Referrer-Policy、CSP frame-ancestors 在响应边界的作用
  2. 对照 prod.conf.example,说出 www 与 admin 在点击劫持防护上的差异
  3. 正确使用 add_header … always,并说明 X-Forwarded-* 与真实 IP(含 CDN 时)如何配合

为什么要学

TLS 解决「传输被窃听」;响应头解决「浏览器怎么对待这份内容」:能否被 iframe、是否强制以后走 HTTPS、是否禁止 MIME 嗅探。
这些头放在 Nginx 统一下发,比每个上游应用各自遗忘更稳。CodeRoadMap 主站与 admin 策略不同:后台更严。
同时,转发头决定 Java 限流与审计看见的「真实客户端」——头设错,安全与风控一起歪。

先建立图像

上游响应(Spring / Next / 静态文件)
        │
        ▼
Nginx 追加安全头 ──► 浏览器执行策略
        │
        └─ 另:请求方向补 X-Forwarded-* ──► 上游记 IP / 协议
头人话
HSTS「以后请只用 HTTPS 来找我」
nosniff「别把文本猜成脚本」
CSP frame-ancestors / X-Frame-Options「谁可以(或不可以)把我嵌进 iframe」
Referrer-Policy「跳出去时带多少来源信息」

跟着做

步骤 1:读主站 add_header

deploy/nginx/prod.conf.example www server:

# always:4xx/5xx 也带上,避免错误页丢 HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;

笔记:

  • HSTS 一年(需站点 HTTPS 已稳定)
  • CSP 此处先管 嵌入策略(frame-ancestors),不是完整脚本 CSP 百科

步骤 2:对比 admin 更严策略

add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;

管理后台:禁止任何站点嵌入,降低点击劫持(用户以为在点后台按钮,实际点到隐藏层)。
主站允许 'self',策略略宽;后台直接封死。

步骤 3:浏览器验证

用已部署环境或本地 HTTPS 实验:

  1. 打开站点 → DevTools → Network → 文档响应
  2. 确认存在 strict-transport-security、x-content-type-options 等
  3. 再看一条 404/502(若可复现)是否 这些头——验证
仍带
always

步骤 4:请求方向的转发头(再钉一次)

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;

Spring 限流、登录审计依赖真实 IP;生成 redirect / cookie 依赖 proto=https。
与 sb-security 的转发头信任配置对照阅读。

步骤 5:前面还有 CDN 时

若 Cloudflare 等在 Nginx 前:

# 示意:只信任 CDN 网段(请换成官方 IP 段)
set_real_ip_from 10.0.0.0/8;
real_ip_header CF-Connecting-IP;  # 或 X-Forwarded-For,按 CDN 文档

否则 $remote_addr 只是 CDN,限流会误伤整网。

步骤 6:与应用头的分工

  • Nginx:边缘统一、错误页也能带上的基线头
  • Next/Spring:业务相关 CSP 脚本策略、CORS(若有独立 API 域)等

避免两边互相覆盖时「只剩一份且更松」——改前先用 curl -I 看最终结果。

步骤 7:用 curl 做一次「边界体检」

在已启用 HTTPS 的环境执行:

curl -sSI https://www.coderoadmap.cn/ | tr -d '\r' | grep -iE 'strict-transport|x-content-type|content-security|referrer-policy'

应能看到本课讨论的基线头。再对一条会 404 的路径重复一次,确认错误响应仍带 always 头。
若某头缺失:先查该 server/location 是否写了 add_header,再查子 location 是否覆盖导致父级头丢失。
把「200 与 4xx 各测一次」写进上线检查清单——安全头验收不能只看首页成功页。

步骤 8:和限流、审计的闭环

真实 IP 不只是日志好看:Spring 侧公开接口限流、异常登录告警都依赖它。
在笔记画一箭头:浏览器 →(可选 CDN)→ Nginx real_ip → X-Forwarded-For → Spring RateLimiter。
任一环信任错对象,都会出现「整网被限」或「攻击者伪造无辜 IP」。本课把头设对,限流课才有正确输入。

讲清楚要点

  1. 因为安全头是给浏览器的策略,所以在 TLS 边界(Nginx)统一添加最省事——上游遗漏也能兜住基线。
  2. 因为默认 add_header 在错误响应可能不生效,所以生产加 always——HSTS 不能只在 200 出现。
  3. 因为后台被嵌入风险更高,所以 admin 用 DENY / frame-ancestors none——主站可略宽。
  4. 因为 HSTS 会「粘」在浏览器里,所以仅在 HTTPS 稳定、跳转正确后启用长 max-age——测坏了难立刻自清。
  5. 因为应用看见的是代理连接,所以必须传 X-Forwarded-*——安全与功能同时依赖。
  6. 因为客户端可伪造 X-Forwarded-For,所以只信任你管控的代理链——CDN 场景用 real_ip。
  7. 因为 nosniff 成本极低收益明确,所以应默认开启——减少错误 Content-Type 被当脚本执行的面。

你可能会懵的地方

  • 只有 CSP frame-ancestors,算不算「上了 CSP」?
    算用了 CSP 的一部分能力。完整防 XSS 的 script-src 策略更复杂,常要前端构建配合;本课先把点击劫持与基线头做对。

  • X-Frame-Options 和 CSP 重复吗?
    有重叠。老客户端认 XFO;现代更推荐 CSP frame-ancestors。admin 两者都上更稳。

  • 为什么 Referrer-Policy 选 no-referrer-when-downgrade?
    同站/升级场景保留有用 referrer;向降级 http 时更谨慎。可按隐私要求再收紧。

  • add_header 在 location 继承有坑?
    若父级有 add_header、子 location 又写了自己的,可能不继承父级那组。改复杂站点前查官方继承行为,或在同一层写全。

  • HSTS 的 includeSubDomains 会不会误伤?
    会把子域也纳入「以后只走 HTTPS」。若某个子域尚未具备有效证书,用户可能暂时打不开。上线前确认 admin/test 等子域 TLS 就绪,或先不用该指令、待全部子域稳妥后再打开。

错法对照

错法问题正解
add_header 无 always错误页丢 HSTS加 always
尚未稳定 HTTPS 就开超长 HSTS用户卡在坏配置先稳定 301/证书再加大 max-age
admin 允许任意 iframe点击劫持面大DENY / frame-ancestors none
盲目信任所有 X-Forwarded-ForIP 伪造只信 CDN/本机代理
只在 Spring 加头、Nginx 错误页无基线不一致边缘统一 + always
子 location 重写 add_header 却漏抄父级部分路径丢 HSTS/CSP同层写全或避免局部覆盖
只验收首页 200错误页无安全头未被发现200 与 4xx 都 curl -I

自测三问

  1. 为什么安全头建议带 always?
  2. www 与 admin 在 frame 相关头上差在哪里?原因是什么?
  3. 有 CDN 时,为何不能直接把 $remote_addr 当用户 IP?

小结一句话

安全头在 Nginx 统一下发(always);admin 更严防嵌入;X-Forwarded- 让 Java 看见真实客户端与 https。*

官方延伸

  • add_header
  • ngx_http_realip_module
加载本节练习…
← 上一课HTTPS 与证书下一课 →缓存与性能