Spring Security 3.2.0.RC1 亮点:安全标头

工程 | Rob Winch | 2013年8月23日 | ...

更新

注意 本博文已不再维护。有关 Spring Security 的 Headers 的最新信息,请参阅 Headers 文档

原文

这是我关于 Spring Security 3.2.0.RC1 系列的第二篇博文。我的 上一篇博文 讨论了 Spring Security 的 CSRF 防护。在这篇文章中,我们将讨论如何使用 Spring Security 添加各种响应标头来帮助保护您的应用程序。

安全标头

Spring Security 3.2.0.RC1 中的许多新功能都是通过向响应添加标头来实现的。这些功能的基础是 Marten Deinum 的辛勤工作。如果这个名字听起来很熟悉,可能是因为他在 Spring 论坛上发布的 10K+ 帖子中的一个帮助过你。

如果您使用 XML 配置,可以使用 Spring Security 的 元素,不带任何子元素,来将所有默认标头添加到响应中。

<http ...>
    ...
    <headers />
</http>

如果您使用 Spring Security 的 Java 配置,默认会添加所有默认安全标头。可以使用下面的 Java 配置禁用它们:

```xml @EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override protected void configure(HttpSecurity http) throws Exception { http .headers().disable() ...; } }


<p>The remainder of this post will discuss each of the default headers in more detail:</p>
<ul>
<li><a href="#cache-control">Cache Control</a></li>
<li><a href="#content-type-options">Content Type Options</a></li>
<li><a href="#hsts">HTTP Strict Transport Security</a></li>
<li><a href="#x-frame-options">X-Frame-Options</a></li>
<li><a href="#x-xss-protection">X-XSS-PROTECTION</a></li>
</ul>
<p><a name="cache-control"></a></p>
<h3>Cache Control</h3>
<p>In the past Spring Security required you to provide your own cache control for your web application. This seemed reasonable at the time, but browser caches have evolved to include caches for secure connections as well. This means that a user may view an authenticated page, log out, and then a malicious user can use the browser history to view the cached page. To help mitigate this Spring Security has added cache control support which will insert the following headers into you response.</p>

```xml
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache

仅添加元素且不带任何子元素将自动添加缓存控制和其他一些保护。但是,如果您只想启用缓存控制,可以使用 Spring Security 的 XML 命名空间,通过 元素来实现。

<http ...>
    ...
    <headers>
        <cache-control />
    </headers>
</http>

类似地,您可以使用下面的 Java 配置仅启用缓存控制:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .headers()
        .cacheControl()
        .and()
      ...;
  }
}

如果您实际上希望缓存特定的响应,您的应用程序可以有选择地调用 HttpServletResponse.setHeader(String,String) 来覆盖 Spring Security 设置的标头。这对于确保 CSS、JavaScript 和图像等内容得到正确缓存非常有用。

在使用 Spring Web MVC 时,通常在您的配置中完成此操作。例如,以下配置将确保所有资源的缓存标头都已设置。

@EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
            .addResourceHandler("/resources/**")
            .addResourceLocations("/resources/")
            .setCachePeriod(31556926);
    }

    // ...
}

内容类型选项

上传文件
允许内容上传时,还有许多其他应采取的措施(例如,仅在不同的域中显示文档,确保设置了 Content-Type 标头,对文档进行清理等)。然而,这些措施超出了 Spring Security 的范畴。另外需要指出的是,在禁用内容嗅探时,您必须指定内容类型才能使操作正常进行。

历史上,包括 Internet Explorer 在内的浏览器会尝试使用 内容嗅探 来猜测请求的内容类型。这允许浏览器通过猜测未指定内容类型的资源来改善用户体验。例如,如果浏览器遇到一个未指定内容类型的 JavaScript 文件,它能够猜测内容类型并执行它。

内容嗅探的问题在于,它允许恶意用户使用多态文件(polyglots)(即,一个文件可以作为多种内容类型有效)来执行 XSS 攻击。例如,一些网站可能允许用户向网站提交一个有效的 postscript 文档并查看它。恶意用户可能会创建一个 也是有效 JavaScript 文件的 postscript 文档,并通过它执行 XSS 攻击。

可以通过向我们的响应添加以下标头来禁用内容嗅探:

X-Content-Type-Options: nosniff

与缓存控制元素一样,当使用元素且不带任何子元素时,nosniff 指令会默认添加。但是,如果您想更好地控制添加哪些标头,可以使用 元素,如下所示:

<http ...>
    ...
    <headers>
        <content-type-options />
    </headers>
</http>

X-Content-Type-Options 标头在 Spring Security Java 配置中是默认添加的。如果您想更好地控制标头,可以显式指定内容类型选项,如下所示:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .headers()
        .contentTypeOptions()
        .and()
      ...;
  }
}

HTTP 严格传输安全 (HSTS)

当您输入您银行的网站时,是输入 mybank.example.com 还是 https://mybank.example.com?如果您省略了 https 协议,您可能会受到 中间人攻击 的威胁。即使网站执行了重定向到 https://mybank.example.com,恶意用户仍然可以拦截初始的 HTTP 请求并操纵响应(例如,重定向到 https://mibank.example.com 并窃取其凭证)。

许多用户会省略 https 协议,这就是 HTTP 严格传输安全 (HSTS) 的创建原因。一旦 mybank.example.com 被添加为 HSTS 主机,浏览器就可以提前知道对 mybank.example.com 的任何请求都应解释为 https://mybank.example.com。这大大降低了发生中间人攻击的可能性。

HSTS 说明
根据 RFC6797,HSTS 标头仅注入到 HTTPS 响应中。为了让浏览器识别该标头,浏览器必须首先信任签署用于建立连接的 SSL 证书的 CA(而不仅仅是 SSL 证书)。

一种将站点标记为 HSTS 主机的方法是将其预加载到浏览器中。另一种方法是将 "Strict-Transport-Security" 标头添加到响应中。例如,以下代码将指示浏览器将该域名视为 HSTS 主机一年(一年大约有 31536000 秒):

Strict-Transport-Security: max-age=31536000 ; includeSubDomains

可选的 includeSubDomains 指令指示 Spring Security 子域(例如 secure.mybank.example.com)也应被视为 HSTS 域。

与其他标头一样,当指定元素且不带任何子元素时,Spring Security 会将上述标头添加到响应中。当您使用 Java 配置时,它也会被自动添加。您也可以仅使用 HSTS 标头,如下面的 元素所示:

<http ...>
    ...
    <headers>
        <hsts />
    </headers>
</http>

类似地,您可以使用 Java 配置仅启用 HSTS 标头:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .headers()
        .hsts()
        .and()
      ...;
  }
}

X-Frame-Options

内容安全策略
处理点击劫持的另一种现代方法是使用 内容安全策略。Spring Security 不支持此功能,因为该规范尚未发布并且相当复杂。要及时了解此问题并查看如何使用 Spring Security 实现它,请参阅 SEC-2117

允许将您的网站添加到框架中可能是一个安全问题。例如,使用巧妙的 CSS 样式,用户可能会被诱骗点击他们不打算点击的内容(视频演示)。例如,登录了银行的用户可能会点击一个授予其他用户访问权限的按钮。这种攻击被称为 点击劫持

有许多方法可以缓解点击劫持攻击。例如,为了保护旧版浏览器免受点击劫持攻击,您可以使用 框架破坏代码。虽然不完美,但框架破坏代码是您为旧版浏览器所能做的最好的。

解决点击劫持的一种更现代的方法是使用 X-Frame-Options 标头。

X-Frame-Options: DENY

X-Frame-Options 响应标头指示浏览器阻止在此响应中标有此标头的任何站点在框架内呈现。与所有其他响应标头一样,当指定元素且不带任何子元素时,此标头会自动包含。您也可以显式指定 元素来控制添加到响应中的标头。

<http ...>
    ...
    <headers>
        <frame-options />
    </headers>
</http>

类似地,您可以使用下面的 Java 配置仅启用框架选项:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .headers()
        .frameOptions()
        .and()
      ...;
  }
}

X-XSS-Protection

某些浏览器内置支持过滤 反射型 XSS 攻击。这绝非万无一失,但确实有助于 XSS 防护。

通常默认启用过滤,因此添加标头通常只是确保其已启用,并指示浏览器在检测到 XSS 攻击时该怎么做。例如,过滤器可能会尝试以侵入性最小的方式更改内容,以便仍然渲染所有内容。有时,这种替换本身可能会成为一个 XSS 漏洞。相反,最好是阻止内容而不是尝试修复它。为此,我们可以添加以下标头:

X-XSS-Protection: 1; mode=block

当指定元素且不带任何子元素时,此标头默认包含。我们可以使用 元素显式声明它,如下所示:

<http ...>
    ...
    <headers>
        <xss-protection />
    </headers>
</http>

类似地,您可以使用下面的 Java 配置仅启用 XSS 防护:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .headers()
        .xssProtection()
        .and()
      ...;
  }
}

反馈

如果您遇到 bug、有改进的想法等,请随时提出!我们希望听到您的想法,以便在代码普遍可用之前确保我们做得正确。尽早试用新功能是回馈社区的一种良好而简单的方式。这也能确保您想要的功能存在并按您期望的方式工作。

请将任何问题或功能请求记录到 Spring Security JIRA。记录 JIRA 后,我们鼓励(但不是必需)您提交您的更改作为 pull request。您可以在 贡献者指南 中阅读更多关于如何执行此操作的信息。

如果您有关于如何做某事的问题,请使用 Spring Security 论坛Stack Overflow 并使用 spring-security 标签(我将密切关注它们)。如果您对这篇博文有任何具体评论或问题,请随时发表评论。使用合适的工具将有助于让每个人都更容易。

结论

您应该对 Spring Security 3.2.RC1 中存在的新功能有了很好的了解。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有