设置HTTP响应头是在浏览器层面上提高Web安全性的一种方法,相比代码层的变动要更简单方便。由于HTTP协议是一个可扩展的协议,这些内容也在不断地变化,本文会试着做一个较为全面的总结。
关于众多浏览器的对响应头的支持、兼容性问题可以在CANIUSE网站搜索了解,示例:
https://caniuse.com/#feat=referrer-policy
部分响应头会有很细节的点无法展开总结,可以参考文末的Web文档进一步了解。
HTTP严格传输安全(HTTP Strict Transport Security)
本响应头,一言以蔽之,是为了防止非HTTPS连接带来的安全隐患。在设置Strict-Transport-Security
响应头后,浏览器将会强制所有的HTTP请求使用HTTPS连接,且在证书错误或到期的情况下拒绝用户访问网站。
值 | 属性 | 描述 |
---|---|---|
max-age |
必选 | 作用时间,单位秒 |
includeSubDomains |
可选 | 作用于所有子域名 |
preload |
可选 | 是否纳入预加载列表 |
需要注意的是,最后的preload
选项添加后,域名会被部分浏览器默认启用HSTS,从而阻止所有HTTP请求连接,因此需要谨慎使用。
响应头设置示例:
Strict-Transport-Security:max-age=31536000;includeSubDomains;preload
由于受信任的CA可能遭受攻击(案例搜一搜有很多),HTTP公钥固定(Public Key Pinning Extension for HTTP)这种安全策略诞生,用于防止替换证书的中间人攻击(MITM)。
其中具体的技术实现包括证书的选择、OpenSSL生成指纹和首次使用信任(TOFU)等。但在这里我不想多总结,因为Chrome自69版本已经移除了对它的支持,有兴趣的同学可以参考RFC7469或MDN Web文档。我们大概来了解一下它就好:
值 | 属性 | 描述 |
---|---|---|
pin-sha256 |
必选 | base64编码的证书的公钥指纹,可添加多个 |
max-age |
必选 | 作用时间,单位秒 |
includeSubdomains |
可选 | HTTP公钥锁定是否覆盖子域 |
report-uri |
可选 | HPKP策略违规报告发送到的URL |
示例:
Public-Key-Pins:
pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=";
pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
report-uri="http://0sec.com.cn/report";
max-age=10000;includeSubDomains
另外还有Public-Key-Pins-Report-Only
头,如字面意思将只报告策略违规而不阻断连接。
用于指示浏览器或客户端验证签名证书的时间戳,是上文的HPKP标头的替代品。
值 | 属性 | 描述 |
---|---|---|
max-age=seconds |
必选 | 作用时间,单位秒 |
enforce |
可选 | 强制模式,拒绝违反策略的连接 |
report-uri |
可选 | CT策略违规报告发送到的的URL |
示例:
Expect-CT:max-age=86400,enforce,report-uri="http://0sec.com.cn/report"
显然是Referer头的安全配置策略,注意单词的拼写,请求头与响应头中的拼写是有差别的,绝了。
值 | 描述 |
---|---|
no-referrer | 不带referer头 |
no-referrer-when-downgrade | 若协议降级如HTTPS到HTTP,则不会发送Referer头(默认策略) |
same-origin | 同源请求才发送Referer头 |
strict-origin | 安全传输(如HTTPS到HTTPS)才发送Referer头 |
origin | Referer头为origin |
origin-when-cross-origin | 同源发送完整URL,跨域发送origin |
strict-origin-when-cross-origin | 安全传输(如HTTPS到HTTPS)同源发送完整URL,跨域发送origin |
unsafe-url | 所有情况发送完整URL,危。 |
示例:
Referrer-Policy: no-referrer
用于设置浏览器或代理的缓存机制,一部分指令也可以用在HTTP请求头中。
值 | 描述 |
---|---|
max-age |
有效时间,单位秒 |
public |
所有内容都将缓存 |
private |
仅在客户端缓存 |
no-cache |
响应无变化时才使用缓存数据 |
no-store |
所有内容均不缓存 |
must-revalidation |
缓存失效则必须重新验证 |
示例:
Cache-Control:max-age=0,no-cache,no-store,must-revalidate
设置当前请求缓存的过期时间,需要注意的是Cache-Control的max-age响应头优先级高于Expires。
为安全起见可以拒绝浏览器缓存任何内容,设置如下:
Expires:0
具体时间格式示例:
Expires:Wed, 21 Oct 2015 07:28:00 GMT
目的是为了减少点击劫持(Clickjacking),最终达成的效果就是站点的<frame>
/<iframe>
/<embed>
/<object>
内容是否被展示。
有三种配置参数:
示例:
x-frame-options:SAMEORIGIN
CSP中的frame-ancestors
选项与x-frame-options
头有同样的作用。
用于启用浏览器的XSS过滤器。
值 | 描述 |
---|---|
0 | 禁用XSS过滤器 |
1 | 启用XSS过滤器 |
1;mode=block | 启用XSS过滤器且在检测到XSS时停止渲染页面 |
1;report=URL | 启用且报告 |
示例(也是推荐的配置方法):
X-XSS-Protection:1,mode=block
当然了,这个XSS过滤器并不太强大,据我测试还是比较容易绕过的。
用于阻止浏览器解析与Content-Type声明不一致的内容。
互联网上的资源有各种类型,通常浏览器会根据响应头的Content-Type字段来分辨它们的类型。例如:"text/html"代表html文档,"image/png"是PNG图片,"text/css"是CSS样式文档。然而,有些资源的Content-Type是错的或者未定义。这时,某些浏览器会启用MIME-sniffing来猜测该资源的类型,解析内容并执行。
例如,我们即使给一个html文档指定Content-Type为"text/plain",在IE8-中这个文档依然会被当做html来解析。利用浏览器的这个特性,攻击者甚至可以让原本应该解析为图片的请求被解析为JavaScript。通过下面这个响应头可以禁用浏览器的类型猜测行为:
以上解释来自Jerry Qu。这个响应头设置方法就是:
X-Content-Type-Options: nosniff
算是应用比较多的响应头,其实就是白名单策略,在之前的文章中详细提过了,直接来看示例:
Content-Security-Policy:script-src 'self'; object-src 'none'; style-src 1.com 2.cn; child-src https
对应下方这张表来看,解释就是:
脚本只信任当前域名;标签不加载任何资源;样式表只信任
http://1.com
和http://2.cn
;框架(frame)必须使用HTTPS协议加载;其他资源没有限制。
指令 | 示例 | 说明 |
---|---|---|
default-src | 'self' cdn.example.com | 定义资源默认加载策略 |
script-src | 'self' js.example.com | 定义 JS 的加载策略 |
img-src | 'self' img.example.com | 定义图片的加载策略 |
style-src | 'self' css.example.com | 定义样式表的加载策略 |
font-src | font.example.com | 定义字体的加载策略、 |
object-src | 'self' | 定义引用资源的加载策略,如<object> <embed><applet> 等 |
media-src | media.example.com | 定义音频和视频的加载策略,如 HTML5 中的<audio><video> |
connect-src | 'self' | 定义 Ajax、WebSocket 等的加载策略 |
frame-src | 'self' | 定义 frame 的加载策略,不赞成使用,改用 child-src |
指定客户端能够访问的跨域策略文件的类型,比如我们熟悉的crossdomain.xml就是一个跨域策略文件。
值 | 描述 |
---|---|
none | 不允许使用策略文件 |
master-only | 仅允许使用主策略文件 |
by-content-type | 仅限HTTP(S)协议使用Content-Type:text-/x-cross-domain-policy 提供的策略文件 |
by-ftp-filename | 仅限FTP协议使用crossdomain.xml |
all | 可用目标域上所有策略文件 |
以X-Frame-Options响应头为例,当然特定的语言、框架有对应的设置方法,这里举服务器配置的例子:
Header [always] set X-Frame-Options "sameorigin"
add_header X-Frame-Options sameorigin [always];
<system.webServer>
...
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="sameorigin" />
</customHeaders>
</httpProtocol>
...
</system.webServer>
setenv.add-response-header = ("X-Frame-Options" => sameorigin",)
新鲜复制的。
Content-Security-Policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com customer-stories-feed.github.com spotlights-feed.github.com; manifest-src 'self'; media-src 'none'; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com
Expect-CT: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
cache-control: private, max-age=0
expires: -1
strict-transport-security: max-age=31536000
x-frame-options: SAMEORIGIN
x-xss-protection: 0
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
content-security-policy: connect-src 'self' blob: https://(太多了); object-src 'none'; script-src 'self' 'unsafe-inline' https://*.twimg.com https://www.google-analytics.com https://twitter.com 'nonce-MDRlMWY3ZTMtM2E5Yi00YjQxLTk5N2UtZTVmYzI5ZjA3ZTY2'; style-src 'self' 'unsafe-inline' https://*.twimg.com; worker-src 'self' blob:; report-uri https://twitter.com/i/csp_report?a=O5RXE%3D%3D%3D&ro=false
pragma: no-cache
strict-transport-security: max-age=631138519
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 0
Analyse your HTTP response headers 在线分析
Check Your HTTP Security Headers 在线分析
Recx Security Analyser Chrome插件
参考