安全相关HTTP响应头解读、配置、示例与检测

设置HTTP响应头是在浏览器层面上提高Web安全性的一种方法,相比代码层的变动要更简单方便。由于HTTP协议是一个可扩展的协议,这些内容也在不断地变化,本文会试着做一个较为全面的总结。

关于众多浏览器的对响应头的支持、兼容性问题可以在CANIUSE网站搜索了解,示例:

https://caniuse.com/#feat=referrer-policy

部分响应头会有很细节的点无法展开总结,可以参考文末的Web文档进一步了解。

响应头解读与示例

HSTS

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

HPKP

由于受信任的CA可能遭受攻击(案例搜一搜有很多),HTTP公钥固定(Public Key Pinning Extension for HTTP)这种安全策略诞生,用于防止替换证书的中间人攻击(MITM)。

其中具体的技术实现包括证书的选择、OpenSSL生成指纹和首次使用信任(TOFU)等。但在这里我不想多总结,因为Chrome自69版本已经移除了对它的支持,有兴趣的同学可以参考RFC7469MDN 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头,如字面意思将只报告策略违规而不阻断连接。

Expect-CT

用于指示浏览器或客户端验证签名证书的时间戳,是上文的HPKP标头的替代品。

属性 描述
max-age=seconds 必选 作用时间,单位秒
enforce 可选 强制模式,拒绝违反策略的连接
report-uri 可选 CT策略违规报告发送到的的URL

示例:

Expect-CT:max-age=86400,enforce,report-uri="http://0sec.com.cn/report"

Referrer-Policy

显然是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

Cache-Control

用于设置浏览器或代理的缓存机制,一部分指令也可以用在HTTP请求头中。

描述
max-age 有效时间,单位秒
public 所有内容都将缓存
private 仅在客户端缓存
no-cache 响应无变化时才使用缓存数据
no-store 所有内容均不缓存
must-revalidation 缓存失效则必须重新验证

示例:

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

Expires

设置当前请求缓存的过期时间,需要注意的是Cache-Control的max-age响应头优先级高于Expires。

为安全起见可以拒绝浏览器缓存任何内容,设置如下:

Expires:0

具体时间格式示例:

Expires:Wed, 21 Oct 2015 07:28:00 GMT

X-Frame-Options

目的是为了减少点击劫持(Clickjacking),最终达成的效果就是站点的<frame>/<iframe>/<embed>/<object>内容是否被展示。

有三种配置参数:

  • DENY:不允许被任何页面嵌入
  • SAMEORIGIN:不允许被本域以外的页面嵌入
  • ALLOW-FROM uri:不允许被指定域名以外的页面嵌入

示例:

x-frame-options:SAMEORIGIN

CSP中的frame-ancestors选项与x-frame-options头有同样的作用。

X-XSS-Protection

用于启用浏览器的XSS过滤器。

描述
0 禁用XSS过滤器
1 启用XSS过滤器
1;mode=block 启用XSS过滤器且在检测到XSS时停止渲染页面
1;report=URL 启用且报告

示例(也是推荐的配置方法):

X-XSS-Protection:1,mode=block

当然了,这个XSS过滤器并不太强大,据我测试还是比较容易绕过的。

X-Content-Type-Options

用于阻止浏览器解析与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(CSP)

算是应用比较多的响应头,其实就是白名单策略,在之前的文章中详细提过了,直接来看示例:

Content-Security-Policy:script-src 'self'; object-src 'none'; style-src 1.com 2.cn; child-src https

对应下方这张表来看,解释就是:

脚本只信任当前域名;标签不加载任何资源;样式表只信任http://1.comhttp://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

X-Permitted-Cross-Domain-Policies

指定客户端能够访问的跨域策略文件的类型,比如我们熟悉的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响应头为例,当然特定的语言、框架有对应的设置方法,这里举服务器配置的例子:

Apache

Header [always] set X-Frame-Options "sameorigin"

Nginx

add_header X-Frame-Options sameorigin [always];

IIS

<system.webServer>
  ...

  <httpProtocol>
    <customHeaders>
      <add name="X-Frame-Options" value="sameorigin" />
    </customHeaders>
  </httpProtocol>

  ...
</system.webServer>

lighthttpd

setenv.add-response-header = ("X-Frame-Options" => sameorigin",)

配置范例

新鲜复制的。

GitHub

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

Google

cache-control: private, max-age=0
expires: -1
strict-transport-security: max-age=31536000
x-frame-options: SAMEORIGIN
x-xss-protection: 0

Twitter

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插件


参考

文章目录
  1. 1. 响应头解读与示例
    1. 1.1. HSTS
    2. 1.2. HPKP
    3. 1.3. Expect-CT
    4. 1.4. Referrer-Policy
    5. 1.5. Cache-Control
    6. 1.6. Expires
    7. 1.7. X-Frame-Options
    8. 1.8. X-XSS-Protection
    9. 1.9. X-Content-Type-Options
    10. 1.10. Content-Security-Policy(CSP)
    11. 1.11. X-Permitted-Cross-Domain-Policies
  2. 2. 配置方法
    1. 2.1. Apache
    2. 2.2. Nginx
    3. 2.3. IIS
    4. 2.4. lighthttpd
  3. 3. 配置范例
    1. 3.1. GitHub
    2. 3.2. Google
    3. 3.3. Twitter
  4. 4. 设置检测工具
|