Spring Security 默认给你加了哪些响应头、漏了哪些?HSTS 什么时候才会出现?怎么把 HTTP 重定向到 HTTPS?放在 Nginx 后面为什么一直 302?这篇在 Spring Boot 4.0.8、Spring Security 7 上起真正的 TLS 和反向代理场景逐项实测。
GET /hello(带凭据) → HTTP 200;cache-control: no-cache, no-store, max-age=0, must-revalidate; expires: 0; pragma: no-cache; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0 GET /hello(不带凭据) → HTTP 401;cache-control: no-cache, no-store, max-age=0, must-revalidate; expires: 0; pragma: no-cache; www-authenticate: Basic realm="Realm"; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0 GET /nope(带凭据,不存在) → HTTP 404;cache-control: no-cache, no-store, max-age=0, must-revalidate; expires: 0; pragma: no-cache; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0 GET /cached(带凭据,控制器自己设了 Cache-Control: max-age=60) → HTTP 200;cache-control: max-age=60; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0 GET /a.txt(带凭据,classpath 的静态文件) → HTTP 200;accept-ranges: bytes; cache-control: no-cache, no-store, max-age=0, must-revalidate; expires: 0; last-modified: Thu, 22 Oct 2026 00:38:00 GMT; pragma: no-cache; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0
nosniff、X-Frame-Options: DENY、X-XSS-Protection: 0、no-store 一组缓存头;控制器自己设的 Cache-Control 不被覆盖;没有 CSP、HSTS(明文下)。
自定义 CSP、frameOptions(sameOrigin)、referrerPolicy(same-origin)、permissionsPolicy → HTTP 200;cache-control: no-cache, no-store, max-age=0, must-revalidate; content-security-policy: default-src 'self'; expires: 0; permissions-policy: geolocation=(); pragma: no-cache; referrer-policy: same-origin; x-content-type-options: nosniff; x-frame-options: SAMEORIGIN; x-xss-protection: 0 headers.disable() → HTTP 200;(没有安全相关的头)
CSP、Referrer-Policy、Permissions-Policy 要自己配;headers.disable() 去掉全部默认头。
[secure] HTTPS GET /hello → HTTP 200;cache-control: no-cache, no-store, max-age=0, must-revalidate; expires: 0; pragma: no-cache; strict-transport-security: max-age=31536000 ; includeSubDomains; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0 [secure] HTTP(端口映射 http→https)GET /hello?x=1 → HTTP 302;Location https://127.0.0.1:<https 端口>/hello?x=1;(没有安全相关的头) [secure-hsts] HTTPS GET /hello → HTTP 200;cache-control: no-cache, no-store, max-age=0, must-revalidate; expires: 0; pragma: no-cache; strict-transport-security: max-age=600; x-content-type-options: nosniff; x-frame-options: DENY; x-xss-protection: 0 requiresChannel(c -> c.anyRequest().requiresSecure())(Spring Security 6 的老写法)→ Caused by: java.lang.NoClassDefFoundError: org/springframework/security/web/access/channel/ChannelEntryPoint | Caused by: java.lang.ClassNotFoundException: org.springframework.security.web.access.channel.ChannelEntryPoint
HSTS 只在 HTTPS 响应里;redirectToHttps 加 portMapper;requiresChannel 老写法 7.0.7 里启动失败。
[没有配置转发头策略] 不带 X-Forwarded-Proto → HTTP 302,Location https://127.0.0.1:9999/hello [没有配置转发头策略] 带 X-Forwarded-Proto: https → HTTP 302,Location https://127.0.0.1:9999/hello,HSTS 无 [server.forward-headers-strategy=framework] 不带 X-Forwarded-Proto → HTTP 302,Location https://127.0.0.1:9999/hello [server.forward-headers-strategy=framework] 带 X-Forwarded-Proto: https → HTTP 200,Location -,HSTS max-age=31536000 ; includeSubDomains [server.forward-headers-strategy=native] 不带 X-Forwarded-Proto → HTTP 302,Location https://127.0.0.1:9999/hello [server.forward-headers-strategy=native] 带 X-Forwarded-Proto: https → HTTP 200,Location -,HSTS max-age=31536000 ; includeSubDomains
代理转发 X-Forwarded-Proto,Boot 配 forward-headers-strategy,否则一直 302。