20. Security HTTP Response Headers(安全超文本传输协议响应头)
本节讨论Spring Security对响应中添加各种安全头的支持。
20.1 Default Security Headers(默认安全表头)
Spring Security允许用户轻松地注入默认安全头,以帮助保护他们的应用程序。Spring Security的默认设置是包含以下标题:
只有在HTTPS请求时才增加Strict-Transport-Security
有关每个标题的更多详细信息,请参考相应的章节:
1、Cache Control 缓存控制
2、Content Type Options 内容类型选项
3、HTTP Strict Transport Security 严格的传输安全
4、X-Frame-Options X-框架-选项
5、X-XSS-Protection X-XSS-保护
虽然这些头都被认为是最佳实践,但应该注意的是,并不是所有的客户端都使用这些头,因此鼓励进行额外的测试。
您可以自定义特定的标题。例如,假设您希望您的HTTP响应头如下所示:
具体来说,您希望所有默认标题都具有以下自定义内容:
1、X-Frame-Options 允许来自同一域的任何请求
2、HTTP Strict Transport Security (HSTS) 不会添加到响应中
您可以通过以下Java配置轻松实现这一点:
或者,如果您正在使用Spring安全XML配置,您可以使用以下内容:
如果您不希望添加默认值,并且希望明确控制应该使用什么,可以禁用默认值。下面提供了一个基于Java和XML的配置示例:
如果您使用的是Spring Security的Java配置,下面将只添加缓存控制。
下面的XML将只添加缓存控制。
如有必要,您可以使用以下Java配置禁用所有HTTP安全响应头:
如有必要,您可以使用下面的XML配置禁用所有的HTTP安全响应头:
20.1.1 Cache Control
过去,Spring Security要求您为web应用程序提供自己的缓存控制。这在当时似乎是合理的,但是浏览器缓存已经发展到包括安全连接的缓存。这意味着用户可以查看经过身份验证的页面,然后注销,然后恶意用户可以使用浏览器历史来查看缓存的页面。为了帮助缓解这种情况,Spring Security增加了缓存控制支持,将在您的响应中插入以下标头。
简单地添加不带子元素的< headers >元素将自动添加缓存控制和许多其他保护。但是,如果您只想要缓存控制,您可以使用Spring Security的带有<cache-control>元素和headers @ default-disabled属性的XML命名空间来启用此功能。
同样,您可以在Java配置中仅启用缓存控制,如下所示:
如果您实际上想要缓存特定的响应,那么您的应用程序可以有选择地调用HttpServletResponse.setHeader(字符串,字符串)来覆盖Spring Security设置的头。这有助于确保像CSS、JavaScript和图像这样的东西被正确缓存。
20.1.2 Content Type Options(内容类型选项)
历史上,浏览器,包括互联网浏览器,会尝试使用内容嗅探来猜测请求的内容类型。这允许浏览器通过猜测没有指定内容类型的资源上的内容类型来改善用户体验。例如,如果浏览器遇到一个没有指定内容类型的JavaScript文件,它将能够猜测内容类型,然后执行它。
当允许内容上传时,有许多额外的事情需要做(例如,只在一个不同的域中显示文档,确保设置了内容类型标题,清理文档,等等)。但是,这些措施超出了Spring Security提供的范围。同样重要的是要指出,当禁用内容嗅探时,您必须指定内容类型,这样事情才能正常工作。
内容嗅探的问题在于,这允许恶意用户使用多语种(即,作为多种内容类型有效的文件)来执行XSS攻击。例如,一些网站可能允许用户向网站提交有效的postscript文档并进行查看。恶意用户可能会创建一个postscript文档,该文档也是一个有效的JavaScript文件,并使用它执行XSS攻击。
通过在我们的响应中添加以下标头,可以禁用内容嗅探:
与缓存控制元素一样,当使用不带子元素的< headers >元素时,默认情况下会添加nosniff指令。但是,如果您想更多地控制添加哪些标题,您可以使用 <content-type-options>元素和 headers@defaults-disabled属性,如下所示:
默认情况下,X-Content-Type-Options标题是通过Spring Security Java配置添加的。如果希望对标题有更多的控制,可以使用以下内容显式指定内容类型选项:
20.1.3 HTTP Strict Transport Security (HSTS)(严格的传输安全(HSTS))
当你输入你的银行网站时,你是进入mybank.example.com还是https://mybank.example.com?如果您忽略https协议,您就有可能受到中间人攻击。即使该网站执行重定向至https://mybank.example.com,恶意用户也可以拦截初始的超文本传输协议请求并操纵响应(即重定向至https://mibank.example.com并窃取其凭据)。
许多用户忽略了https协议,这就是为什么创建了HTTP严格传输安全(HSTS)。一旦mybank.example.com被添加为HSTS配置,浏览器可以提前知道任何对mybank.example.com的请求都应该被解释为https://mybank.example.com。这大大降低了中间人攻击发生的可能性。根据RFC6797,HSTS标题仅注入HTTPS响应。为了让浏览器确认报头,浏览器必须首先信任签署用于建立连接的SSL证书(而不仅仅是SSL证书)的证书颁发机构。
将网站标记为HSTS主机的一种方法是将主机预加载到浏览器中。另一种方法是在响应中添加“严格传输安全性”标题。例如,下面将指示浏览器在一年内将该域视为HSTS主机(一年大约有31536000秒):
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
可选的includeSubDomains指令指示Spring Security将子域(即secure.mybank.example.com)也视为HSTS域。与其他头一样,默认情况下,Spring Security会添加HSTS。您可以使用< hsts >元素自定义HSTS标题,如下所示:
同样,您只能使用Java配置启用HSTS标头:
20.1.4 HTTP Public Key Pinning (HPKP)(超文本传输协议公钥锁定(HPKP))
超文本传输协议公钥锁定(HPKP)是一项安全功能,它告诉网络客户端将特定的加密公钥与某个网络服务器相关联,以防止中间人(MITM)利用伪造的证书进行攻击。
为了确保在TLS会话中使用的服务器公钥的真实性,该公钥被封装到通常由证书颁发机构(CA)签名的X.509证书中。浏览器等网络客户端信任很多这样的CA,它们都可以为任意域名创建证书。如果攻击者能够危害单个CA,他们可以对各种顶级域名系统连接执行MITM攻击。HPKP可以通过告诉客户端哪个公钥属于某个web服务器来规避HTTPS协议的威胁。HPKP是第一次使用(TOFU)技术信托。当网络服务器第一次通过一个特殊的超文本传输协议头告诉客户端哪些公钥属于它时,客户端会将这些信息存储一段时间。当客户端再次访问服务器时,它需要一个包含公钥的证书,该公钥的指纹已经通过HPKP知道了。如果服务器传递了未知的公钥,客户端应该向用户发出警告。
因为用户代理需要根据SSL证书链验证pin,所以HPKP报头只被注入到HTTPS响应中。
为您的站点启用此功能就像在通过HTTPS访问您的站点时返回公钥密码一样简单。例如,下面将指示用户代理只向给定的URI(通过report-uri指令)报告两个pin的pin验证失败:
Public-Key-Pins-Report-Only: max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; report-uri="https://example.net/pkp-report" ; includeSubDomains
pin验证失败报告是一种标准的JSON结构,可以由网络应用程序自己的应用编程接口捕获,也可以由公共托管的HPKP报告服务捕获,如URI报告。
可选的includeSubDomains指令指示浏览器也用给定的pin验证子域。
与其他标题相反,默认情况下,Spring Security不会添加HPKP。您可以使用< hpkp >元素自定义HPKP标题,如下所示:
同样,您可以使用Java配置启用HPKP标头:
20.1.5 X-Frame-Options
允许您的网站被添加到框架中可能是一个安全问题。例如,使用聪明的CSS样式的用户可能会被骗去点击他们不想点击的东西。例如,登录到其银行的用户可能会单击授予其他用户访问权限的按钮。这种攻击被称为点击劫持。
处理点击劫持的另一种现代方法是使用第20.1.7节“内容安全策略(CSP)”。
有许多方法可以减轻点击劫持攻击。例如,为了保护传统浏览器免受点击劫持攻击,您可以使用框架破坏代码。虽然不完美,但框架中断代码是遗留浏览器的最佳选择。
解决点击劫持的一个更现代的方法是使用X-Frame-Options标题:X-Frame-Options: DENY
X-Frame-Options响应头指示浏览器阻止响应中带有此头的任何站点在帧内呈现。默认情况下,Spring Security禁用iframe中的呈现。您可以使用框架选项元素来自定义框架选项。例如,下面将指示Spring Security使用“X-Frame-Options: SAMEORIGIN”,它允许在同一个域中使用iframe:、
您可以使用框架选项元素来自定义框架选项。例如,下面将指示Spring Security使用“X-Frame-Options: SAMEORIGIN”,它允许在同一个域中使用iframe:
同样,您可以使用以下内容自定义框架选项,以便在Java配置中使用相同的原点:
20.1.6 X-XSS-Protection
一些浏览器内置了过滤反射XSS攻击的支持。这绝非万无一失,但确实有助于保护XSS。
默认情况下,过滤通常是启用的,因此添加标头通常只是确保它已启用,并指示浏览器在检测到XSS攻击时该做什么。例如,过滤器可能试图以最小的侵入方式改变内容,以仍然呈现所有内容。有时,这种替代方式本身就可能成为XSS的一个弱点。相反,最好是阻止内容,而不是试图修复它。为此,我们可以添加以下标题:X-XSS-Protection: 1; mode=block
默认情况下会包含此标题。然而,如果我们愿意,我们可以定制它。例如:
同样,您可以使用以下内容在Java配置中自定义XSS保护:
20.1.7 Content Security Policy (CSP)(内容安全策略)
内容安全策略(CSP)是一种机制,网络应用程序可以利用它来减轻内容注入漏洞,如跨站点脚本(XSS)。CSP是一种声明性策略,它为web应用程序作者提供了一种工具,可以声明并最终通知客户端(用户代理)web应用程序期望从其加载资源的来源。
内容安全策略并非旨在解决所有内容注入漏洞。相反,可以利用CSP来帮助减少内容注入攻击造成的危害。作为第一道防线,web应用程序作者应该验证他们的输入并对他们的输出进行编码。
网络应用程序可以通过在响应中包含以下一个HTTP头来使用CSP:
Content-Security-Policy
Content-Security-Policy-Report-Only
这些报头中的每一个都被用作向客户端传递安全策略的机制。安全策略包含一组安全策略指令(例如,脚本-src和对象-src),每个指令负责声明特定资源表示的限制。
例如,web应用程序可以通过在响应中包含以下标头来声明它期望从特定的可信来源加载脚本:
Content-Security-Policy: script-src https://trustedscripts.example.com
用户代理将阻止从脚本-src指令中声明的以外的其他源加载脚本的尝试。此外,如果在安全策略中声明了report-uri指令,则用户代理将向声明的URL报告违规。
例如,如果一个web应用程序违反了声明的安全策略,下面的响应头将指示用户代理向策略的报告uri指令中指定的URL发送违反报告。
Content-Security-Policy: script-src https://trustedscripts.example.com; report-uri /csp-report-endpoint/
违规报告是标准的JSON结构,可以由网络应用程序自己的应用编程接口捕获,也可以由公共托管的CSP违规报告服务捕获,如URI报告。
The Content-Security-Policy-Report-Only header为网络应用程序作者和管理员提供了监视安全策略的能力,而不是强制实施它们。此标头通常用于试验和/或开发网站的安全策略。当策略被认为有效时,可以通过使用Content-Security-Policy 标题字段来实施。
给定下面的响应头,策略声明脚本可以从两个可能的来源之一加载。
如果站点违反此策略,通过尝试从evil.com加载脚本,用户代理将向report-uri指令指定的声明的URL发送一个违反报告,但仍然允许违反的资源加载。
Configuring Content Security Policy(置内容安全策略 )
需要注意的是,默认情况下,Spring Security不会添加内容安全策略。web应用程序作者必须声明安全策略来实施和/或监控受保护的资源。
例如,给定以下安全策略:
您可以使用带有 <content-security-policy>元素的XML配置来启用CSP头,如下所示:
<http>
<headers>
<content-security-policy policy-directives ="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" />
</headers>
</http>
要启用CSP“report-only”标题,请按如下方式配置元素:
<http>
<headers>
<content-security-policy policy-directives ="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" report-only="true" />
</headers>
</http>
同样,您可以使用如下所示的Java配置来启用CSP头:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(HttpSecurity http)throws Exception {
http
// ....
headers().contentSecurityPolicy("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/");
}
}
要启用CSP“仅报告”标题,请提供以下Java配置:
将内容安全策略应用于web应用程序通常是一项不简单的工作。以下资源可能会为您的站点制定有效的安全策略提供进一步的帮助。
An Introduction to Content Security Policy
CSP Guide - Mozilla Developer Network
20.1.8 Referrer Policy(引荐者策略)
引荐者策略是一种机制,网络应用程序可以利用它来管理引荐者字段,该字段包含用户所在的最后一页。Spring Security的方法是使用引用者策略头,它提供不同的策略:
引用者-策略响应头指示浏览器让目的地知道用户先前所在的源。
Configuring Referrer Policy(配置推荐人策略)
默认情况下,Spring Security不会添加引用者策略头。
您可以使用带有<referrer-policy> 元素的XML配置来启用推荐人-策略标题,如下所示:
同样,您可以使用如下所示的Java配置来启用引用者策略头:
20.2 Custom Headers(自定义标题)
20.2.1 Static Headers(静态头部)
有时,您可能希望在应用程序中注入不支持的自定义安全头。例如,给定以下自定义安全标头:
当使用XML命名空间时,可以使用< header >元素将这些头添加到响应中,如下所示:
同样,可以使用Java配置将头添加到响应中,如下所示:
20.2.2 Headers Writer
当命名空间或Java配置不支持您想要的头时,您可以创建一个自定义的头编写器实例,甚至提供头编写器的自定义实现。
让我们来看一个使用XFrameOptionsHeaderWriter的自定义实例的例子。也许您希望允许为相同的源构建内容框架。这很容易通过将策略属性设置为“SAMEORIGIN”来支持,但是让我们看一个使用ref属性的更明确的例子。
我们还可以用Java配置将内容的框架限制在同一个来源:
20.2.3 Delegating Request Matcher Header Writer(委托请求匹配器标题编写器)
有时,您可能只想为某些请求编写一个标头。例如,也许您只想保护您的登录页面不被陷害。您可以使用delegatingrequestmatcheerheader writer来实现这一点。使用XML命名空间配置时,可以通过以下方式完成:
我们还可以使用java配置来防止将内容框架化到登录页面: