header的安全配置指南

共计 7025 个字符,预计需要花费 18 分钟才能阅读完成。

from: http://drops.wooyun.org/tips/1166

0x00 背景


在统计了 Alexa top 100 万网站的 header 安全分析之后(2012 年 11 月 – 2013 年 3 月 – 2013 年 11 月),我们发现其实如何正确的设置一个 header 并不是一件容易的事情。尽管有数不胜数的网站会使用大量有关安全方面的 header,但并没有一个像样的平台能够为开发者们提供必要的信息,以辨别那些常见的错误设置。或者说,即使这些安全方面的 header 设置正确了,也没有一个平台能够为开发者提供一个系统的测试方法,用来测试正确与否。这些 header 如果设置错误了不仅会产生安全的假象,甚至会对网站的安全产生威胁。veracode 认为安全性 header 是网络防护中非常重要的一环,并且他希望让开发者们能够简捷、正确地设置站点。如果您对某一 header 或设置有任何疑问,我们有极好的资源能够追踪到浏览器支持情况。

 

0x01 细节


1. X-XSS-Protection

目的

这个 header 主要是用来防止浏览器中的反射性 xss。现在,只有 IE,chrome 和 safari(webkit)支持这个 header。

正确的设置

0 – 关闭对浏览器的 xss 防护  1 – 开启 xss 防护  1; mode=block – 开启 xss 防护并通知浏览器阻止而不是过滤用户注入的脚本。1; report=http://site.com/report – 这个只有 chrome 和 webkit 内核的浏览器支持,这种模式告诉浏览器当发现疑似 xss 攻击的时候就将这部分数据 post 到指定地址。

通常不正确的设置

0; mode=block; – 记住当配置为 0 的时候,即使加了 mode=block 选项也是没有效果的。需要指出的是,chrome 在发现这种错误的配置后还是会开启 xss 防护。1 mode=block; – 数字和选项之间必须是用分号分割,逗号和空格都是错误的。但是这种错误配置情况下,IE 和 chrome 还是默认会清洗 xss 攻击,但是不会阻拦。

如何检测

如果过滤器检测或阻拦了一个反射性 xss 以后,IE 会弹出一个对话框。当设置为 1 时,chrome 会隐藏对反射性 xss 的输出。如果是设置为 1; mode=block , 那么 chrome 会直接将 user-agent 置为一个空值:, URL  这种形式。

参考文献

Post from Microsoft on the X-XSS-Protection Header
Chromium X-XSS-Protection Header Parsing Source
Discussion of report format in WebKit bugzilla

2. X-Content-Type-Options

目的

这个 header 主要用来防止在 IE9、chrome 和 safari 中的 MIME 类型混淆攻击。firefox 目前对此还存在争议。通常浏览器可以通过嗅探内容本身的方法来决定它是什么类型,而不是看响应中的 content-type 值。通过设置 X-Content-Type-Options:如果 content-type 和期望的类型匹配,则不需要嗅探,只能从外部加载确定类型的资源。举个例子,如果加载了一个样式表,那么资源的 MIME 类型只能是 text/css,对于 IE 中的脚本资源,以下的内容类型是有效的:

application/ecmascript  application/javascript  application/x-javascript  text/ecmascript  text/javascript  text/jscript  text/x-javascript  text/vbs  text/vbscript  

对于 chrome,则支持下面的 MIME 类型:

text/javascript  text/ecmascript  application/javascript  application/ecmascript  application/x-javascript  text/javascript1.1  text/javascript1.2  text/javascript1.3  text/jscript  text/live script

正确的设置

nosniff – 这个是唯一正确的设置,必须这样。

通常不正确的设置

‘nosniff’– 引号是不允许的  : nosniff – 冒号也是错误的 

如何检测

在 IE 和 chrome 中打开开发者工具,在控制台中观察配置了 nosniff 和没有配置 nosniff 的输出有啥区别。

参考文献

Microsoft Post on Reducing MIME type security risks
Chromium Source for parsing nosniff from response
Chromium Source list of JS MIME types
MIME Sniffing Living Standard

3. X-Frame-Options

目的

这个 header 主要用来配置哪些网站可以通过 frame 来加载资源。它主要是用来防止 UI redressing 补偿样式攻击。IE8 和 firefox 18 以后的版本都开始支持 ALLOW-FROM。chrome 和 safari 都不支持 ALLOW-FROM,但是 WebKit 已经在研究这个了。

正确的设置

DENY – 禁止所有的资源(本地或远程)试图通过 frame 来加载其他也支持 X -Frame-Options 的资源。SAMEORIGIN – 只允许遵守同源策略的资源(和站点同源)通过 frame 加载那些受保护的资源。ALLOW-FROM http://www.example.com – 允许指定的资源(必须带上协议 http 或者 https)通过 frame 来加载受保护的资源。这个配置只在 IE 和 firefox 下面有效。其他浏览器则默认允许任何源的资源(在 X -Frame-Options 没设置的情况下)。

通常不正确的设置

ALLOW FROM http://example.com – ALLOW 和 FROM 之间只能通过连字符来连接,空格是错误的。ALLOW-FROM example.com – ALLOW-FROM 选项后面必须跟上一个 URI 而且要有明确的协议(http 或者 https)

如何检测

可以通过访问 test cases 来查看各种各样的选项 和浏览器对这些 frame 中的资源的响应。

参考文献

X-Frame-Options RFC
Combating ClickJacking With X-Frame-Options

4. Strict-Transport-Security

目的

Strict Transport Security (STS) 是用来配置浏览器和服务器之间安全的通信。它主要是用来防止中间人攻击,因为它强制所有的通信都走 TLS。目前 IE 还不支持 STS 头。需要注意的是,在普通的 http 请求中配置 STS 是没有作用的,因为攻击者很容易就能更改这些值。为了防止这样的现象发生,很多浏览器内置了一个配置了 STS 的站点 list。

正确的设置
注意下面的值必须在 https 中才有效,如果是在 http 中配置会没有效果。

max-age=31536000 – 告诉浏览器将域名缓存到 STS list 里面,时间是一年。max-age=31536000; includeSubDomains – 告诉浏览器将域名缓存到 STS list 里面并且包含所有的子域名,时间是一年。max-age=0 – 告诉浏览器移除在 STS 缓存里的域名,或者不保存此域名。

通常不正确的设置

直接将 includeSubDomains 设置为 https://www.example.com,但是用户依然可以通过 http://example.com 来访问此站点。如果 example.com 并没有跳转到 https://example.com 并设置 STS header,那么访问 http://www.example.com 就会直接被浏览器重定向到 https://www.example.com。max-age=60 – 这个只设置域名保存时间为 60 秒。这个时间太短了,可能并不能很好的保护用户,可以尝试先通过 http 来访问站点,这样可以缩短传输时间。max-age=31536000 includeSubDomains – max-age 和 includeSubDomains 直接必须用分号分割。这种情况下,即使 max-age 的值设置的没有问题,chrome 也不会将此站点保存到 STS 缓存中。max-age=31536000, includeSubDomains – 同上面情况一样。max-age=0 – 尽管这样在技术上是没有问题的,但是很多站点可能在处理起来会出差错,因为 0 可能意味着永远不过期。

如何检测

判断一个主机是否在你的 STS 缓存中,chrome 可以通过访问 chrome://net-internals/#hsts,首先,通过域名请求选项来确认此域名是否在你的 STS 缓存中。然后,通过 https 访问这个网站,尝试再次请求返回的 STS 头,来决定是否添加正确。

参考文献

Strict Transport Security RFC6797
Wikipedia page on Strict Transport Security (with examples)

5. Public-Key-Pins (起草中)

目的

有关这个 header 的详细描述还在起草中,但是它已经有了很清晰的安全作用,所以我还是把它放在了这个 list 里面。Public-Key-Pins (PKP)的目的主要是允许网站经营者提供一个哈希过的公共密钥存储在用户的浏览器缓存里。跟 Strict-Transport-Security 功能相似的是,它能保护用户免遭中间人攻击。这个 header 可能包含多层的哈希运算,比如 pin-sha256=base64(sha256(SPKI)),具体是先将 X.509 证书下的 Subject Public Key Info (SPKI) 做 sha256 哈希运算,然后再做 base64 编码。然而,这些规定有可能更改,例如有人指出,在引号中封装哈希是无效的,而且在 33 版本的 chrome 中也不会保存 pkp 的哈希到缓存中。

这个 header 和 STS 的作用很像,因为它规定了最大子域名的数量。此外,pkp 还提供了一个 Public-Key-Pins-Report-Only 头用来报告异常,但是不会强制阻塞证书信息。当然,这些 chrome 都是不支持的。

正确的设置

max-age=3000; pin-sha256=”d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=”; – 规定此站点有 3000 秒的时间来对 x.509 证书项目中的公共密钥信息(引号里面的内容)做 sha256 哈希运算再做 base64 编码。max-age=3000; pin-sha256=”d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=”; report-uri=”http://example.com/pkp-report”– 同上面一样,区别是可以报告异常。

通常不正确的设置

max-age=3000; pin-sha256=d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=; – Not encapsulating the hash value in quotes leads to Chrome 33 not adding the keys to the PKP cache. This mistake was observed in all but one of the four sites that returned this or the report-only header response. 没有添加引号,这样的话 chrome 不会将这个 key 添加到 PKP 缓存中。我们的调查中发现有四分之一的网站存在此问题。

如何检测

如果站点成功的将 pkp 哈希存入了客户端缓存,那么使用和 Strict-Transport-Security(STS)相同的方法查看 pubkey_hashes 信息就可以了。

参考文献

Public-Key-Pins draft specification
Chrome issue tracking the implementation of Public-Key-Pins
Chromium source code for processing Public-Key-Pins header

6. Access-Control-Allow-Origin

目的

Access-Control-Allow-Origin 是从 Cross Origin Resource Sharing (CORS)中分离出来的。这个 header 是决定哪些网站可以访问资源,通过定义一个通配符来决定是单一的网站还是所有网站可以访问我们的资源。需要注意的是,如果定义了通配符,那么 Access-Control-Allow-Credentials 选项就无效了,而且 user-agent 的 cookies 不会在请求里发送。

正确的设置

* – 通配符允许任何远程资源来访问含有 Access-Control-Allow-Origin 的内容。http://www.example.com – 只允许特定站点才能访问(http://[host], 或者 https://[host])

通常不正确的设置

http://example.com, http://web2.example.com – 多个站点是不支持的,只能配置一个站点。*.example.com – 只允许单一的站点  http://*.example.com – 同上面一样  

如何检测

很容易就能确定这个 header 是否被设置的正确,因为如果设置错误的话,CORS 请求就会接收不到数据。

参考文献

W3C CORS specification
Content-Security-Policy 1.0

目的

csp 是一些指令的集合,可以用来限制页面加载各种各样的资源。目前,IE 浏览器只支持 CSP 的一部分,而且仅支持 X -Content-Security-Policy header。相比较而言,Chrome 和 Firefox 则支持 CSP 的 1.0 版本,csp 的 1.1 版本则还在开发中。通过恰当的配置 csp,可以防止站点遭受很多类型的攻击,譬如 xss 和 UI 补偿等相关问题。

csp 总共有 10 种配置形式,每一种都可以用来限制站点何时加载和加载何种类型的资源。他们分别是:

default-src:这种形式默认设置为 script-src, object-src, style-src, img-src, media-src, frame-src, font-src 和 connect-src. 如果上述设置一个都没有的话,user-agent 就会被用来作为 default-src 的值。

script-src:这种形式也有两个附加的设置。

1、unsafe-inline:允许资源执行脚本。举个例子,on 事件的值会被编码到 html 代码中,或者脚本元素的 text 的内容会被混入到受保护的资源中。2、unsafe-eval:允许资源动态的执行函数,比如 eval,setTimeout, setInterval, new 等函数。

object-src – 决定从哪里加载和执行插件。
style-src – 决定从哪里加载 css 和样式标记。
img-src – 决定从哪里加载图片。
media-src – 决定从哪里加载视频和音频资源。
frame-src – 决定哪里的 frames 可以被嵌入。
font-src – 决定从哪里加载字体。
connect-src – 限制在 XMLHttpRequest, WebSocket 和 EventSource 中可以使用哪些类型的资源。
sandbox – 这是一个可选形式,它决定了沙盒的策略,如何将内容嵌入到沙盒中以保证安全。

当这个策略被特定的 url 违反了,我们也可以用报告地址直接发送报告。这样做有利于 debug 和当攻击发生时通知我们。

此外,我们可以定义 Content-Security-Policy-Report-Only 的 header 不强制遵守 csp,但是会发送潜在的威胁到一个报告地址。它遵守和 csp 一样的语法和规则。

正确的设置

View cspplayground.com compliant examples  

通常不正确的设置:

View cspplayground.com violation examples  

如何检测

在 chrome 和 firefox 中打开开发者工具或者 firebug,在控制台查看是否有潜在的威胁。

参考文献

Content Security Policy 1.0 Specification
Content Security Policy 1.1 Working Draft Specification
cspplayground.com’s excellent collection of resources for CSP
Sublime Text 2 Plugin for validating HTML/JS while you code your site

关于 Alexa 排名 top 100 万网站的安全 header 的研究

正文完
 
zhaopeng
版权声明:本站原创文章,由 zhaopeng 2015-03-14发表,共计7025字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)