安全 HTTP 响应标头 可用于提高 Web 应用程序的安全性
Spring Security 提供了一 组默认的 Security HTTP Response Headers 来提供安全的默认值。 虽然这些标头中的每一个都被认为是最佳实践,但应注意并非所有客户端都使用标头,因此鼓励进行额外测试。
您可以自定义特定的Header
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.frameOptions(frameOptions -> frameOptions
.sameOrigin()
)
);
return http.build();
}
}
如果您不想添加默认值并希望明确控制应该使用的内容,则可以禁用默认值
http.headers(headers -> headers.defaultsDisabled());
以这种方式会禁止默认的安全头,除非我们自己指出
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers.disable());
return http.build();
}
}
Spring Security 默认包含 Cache Control 标头。
Spring Security 的默认设置是禁用缓存以保护用户的内容
但是,如果您确实想要缓存特定的响应,您的应用程序可以选择性地调用 HttpServletResponse.setHeader(String,String) 来覆盖 Spring Security 设置的标头。 这对于确保正确缓存 CSS、JavaScript 和图像等内容很有用。
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.defaultsDisabled()
.cacheControl(withDefaults())
);
return http.build();
}
}
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.cacheControl(cache -> cache.disable())
);
return http.build();
}
}
默认包含Content-Type
当允许上传内容时,还应该做很多额外的事情(即只在不同的域中显示文档,确保设置 Content-Type 标头,清理文档等)。 但是,这些措施超出了 Spring Security 提供的范围。 同样重要的是要指出禁用内容嗅探时,您必须指定内容类型才能正常工作。
内容嗅探的问题在于,这允许恶意用户使用多语言(即作为多种内容类型有效的文件)来执行 XSS 攻击。 例如,某些网站可能允许用户向网站提交有效的 postscript 文档并进行查看。 恶意用户可能会创建一个 也是有效 JavaScript 文件的 postscript 文档 并使用它执行 XSS 攻击
Spring Security 默认通过向 HTTP 响应添加以下标头来禁用内容嗅探
X-Content-Type-Options: nosniff
当然也是可以禁用的但是很不推荐你这样做
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
);
return http.build();
}
}
简单来说,对于需要高安全性的网站我们会使用Https协议,因为恶意用户可以拦截初始 HTTP 请求并操纵响应,https协议会大大提升安全性,降低中间人攻击行为
根据 RFC6797 ,HSTS 标头仅注入到 HTTPS 响应中。 为了让浏览器确认标头,浏览器必须首先信任签署用于建立连接的 SSL 证书的 CA(而不仅仅是 SSL 证书)。
Spring Security 默认提供 Strict Transport Security 标头。 但是,您可以显式自定义结果
指示浏览器将域视为 HSTS 主机一年
Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.preload(true)
.maxAgeInSeconds(31536000)
)
);
return http.build();
}
}
允许将您的网站添加到框架中可能是一个安全问题。 例如,使用巧妙的 CSS 样式可能会诱使用户点击他们不希望的内容。 例如,登录到其银行的用户可能会单击授予其他用户访问权限的按钮。 这种攻击被称为 Clickjacking
处理点击劫持的另一种现代方法是使用 内容安全策略 (CSP)
解决点击劫持的一种更现代的方法是使用 X-Frame-Options 标头。 默认情况下,Spring Security 使用以下标头禁用 iframe 内的渲染页面
X-Frame-Options: DENY
解释一下:如果两个页面,协议,域名,端口都一致,则为同源
我们现在一般都是使用跨域(前后端分离)
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.frameOptions(frameOptions -> frameOptions
.sameOrigin()
)
);
return http.build();
}
}
一些浏览器内置了过滤 反射 XSS 攻击,例如Chrome,firefox,但我们为了安全还需要进行设置
通常是默认启用,因此添加标头通常只是确保启用它并指示浏览器在检测到 XSS 攻击时该怎么做。 例如,过滤器可能会尝试以侵入性最小的方式更改内容以仍然呈现所有内容。 有时,这种类型的替换本身可能会成为 XSS 漏洞 。 相反,最好阻止内容而不是尝试修复它
默认情况下,Spring Security 使用
指示浏览器阻止反射型 XSS 攻击。 但是,您可以更改此默认值。
X-XSS-Protection: 1; mode=block
以下配置指定 Spring Security 不应再指示浏览器阻止内容
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.xssProtection(xss -> xss
.block(false)
)
);
return http.build();
}
}
内容安全策略 (CSP) 是一种机制,Web 应用程序可以利用它来缓解内容注入漏洞,例如跨站点脚本 (XSS)。 CSP 是一种声明性策略,它为 Web 应用程序作者提供了一种工具来声明并最终通知客户端(用户代理)有关 Web 应用程序期望从中加载资源的源。
内容安全策略并非旨在解决所有内容注入漏洞。 相反,可以利用 CSP 来帮助减少内容注入攻击造成的危害。 作为第一道防线,Web 应用程序作者应该验证他们的输入并编码他们的输出。
Spring Security 默认不添加 Content Security Policy,因为没有应用程序的上下文就不可能知道合理的默认值。 Web 应用程序作者必须声明安全策略以强制执行和/或监控受保护资源
Web 应用程序可以通过在响应中包含以下标头来声明它希望从特定的可信来源加载脚本
Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/
尝试从其他源加载脚本,而不是在 script-src
指令将被用户代理阻止。 此外,如果在安全策略中声明了 report-uri
指令,则用户代理将向声明的 URL 报告违规行为
如果 Web 应用程序违反了声明的安全策略,则以下响应标头将指示用户代理将违反报告发送到策略中指定的 URL report-uri
指示
Content-Security-Policy: script-src https://trustedscripts.example.com; report-uri /csp-report-endpoint/
违规报告 是标准 JSON 结构
这 Content-Security-Policy-Report-Only标头为 Web 应用程序作者和管理员提供了监控安全策略的能力,而不是强制执行它们。 此标头通常在为站点试验和/或开发安全策略时使用
给定以下响应标头,该策略声明可以从两个可能的来源之一加载脚本
Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.example.com; report-uri /csp-report-endpoint/
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
一个网站管理者想要所有内容均来自站点的同一个源 (不包括其子域名)
Content-Security-Policy: default-src 'self'
一个网站管理者允许内容来自信任的域名及其子域名 (域名不必须与 CSP 设置所在的域名相同)
Content-Security-Policy: default-src 'self' *.trusted.com
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
)
);
return http.build();
}
}
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
.reportOnly()
)
);
return http.build();
}
}
因为我们通常前后端分离的项目中采用前端进行一些简单的持久化处理,如吧图片,等信息存储再localStorage中,前端会进行一些处理,后端则负责自己的一些即可
清除站点数据 是一种机制,当 HTTP 响应包含此标头时,可以通过该机制删除任何浏览器端数据(cookie、本地存储等)这是在注销时执行的一个很好的清理操作:
Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
这里清除了cache和cookie
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.logout((logout) -> logout
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES)))
);
return http.build();
}
}
这里我就不介绍了,大家可以看官网,我推荐是使用SpringSecurity的CORS进行跨域配置,而不是使用跨域标头
当然我们也可以自定义一些Header,前后端分离里你需要与前后端约定好,这样
以下配置将标头添加到响应中
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
);
return http.build();
}
}