HTTP响应头安全问题处理记录
为了提升博客的安全性,用https://securityheaders.com/对博客的HTTP响应头进行了检测,不查不知道,一查吓一跳,按照SecurityHeaders的评分标准只获得了D级别(最低F,最高A+),因此决定对博客的HTTP响应头进行一次规范化处理并记录全过程。
Content-Security-Policy(CSP)
内容安全策略(Content Security Policy,简称CSP)是一种以可信白名单作机制,来限制网站是否可以包含某些来源内容,缓解广泛的内容注入漏洞,比如XSS、点击劫持、SQL注入等等,CSP通过定义运行加载脚本的位置和内容防止恶意代码的加载。简单来说,就是我们能够规定,我们的网站只接受我们指定的请求资源,默认配置下不允许执行内联代码。
响应头
- Content-Security-Policy
- X-Content-Security-Policy(旧版)
- X-Webkit-CSP
使用方法
CSP可以由两种方式指定:HTTP Header
和HTML
,如果两种方式同时定义了CSP,则会优先采用HTTP Header
的。
通过定义在HTTP Header
中使用
1 | Content-Security-Policy: default-src 'self' |
通过定义在meta标签
中使用
1 | <meta http-equiv="content-security-policy" content="default-src 'self'"> |
- 策略是指定义CSP的语法内容,一个策略由一系列策略指令组成,每个策略指令都描述了一个针对某个特定类型资源以及生效范围的策略。
- 定义后,凡是不符合CSP策略的外部资源都会被阻止加载。
CSP语法
每一条策略都由指令与指令值组成
1 | Content-Security-Policy:指令1 指令值1 |
多个指令之间使用英文分号
1 | Content-Security-Policy:指令1 指令值1;指令2 指令值2;指令3 指令值3 |
如果一个指令中有多个指令值,则多个指令值之间用英文空格分割
1 | Content-Security-Policy:指令a 指令值a1 指令值a2 |
CSP指令
指令 | 说明 |
---|---|
default-src | 定义针对所有类型(js/image/css/font/ajax/iframe/多媒体等)资源的默认加载策略,如果某类型资源没有单独定义策略,就使用默认的。 |
script-src | 定义针对JavaScript的加载策略。 |
style-src | 定义针对样式的加载策略。 |
img-src | 定义针对图片的加载策略。 |
font-src | 定义针对字体的加载策略。 |
media-src | 定义针对多媒体的加载策略,例如音频标签<audio> 和视频标签<video> 。 |
object-src | 定义针对插件的加载策略,例如<object> 、<embed> 、<applet> 等标签引入的Flash等插件 |
child-src | 定义针对框架的加载策略,例如: ,。 |
connect-src | 定义针对Ajax/WebSocket等请求的加载策略。不允许的情况下,浏览器会模拟一个状态为400的响应。 |
sandbox | 对请求的资源启用sandbox(类似于iframe的sandbox属性)。 |
report-uri | 告诉浏览器如果请求的资源不被策略允许时,往哪个地址提交日志信息。如果想让浏览器只汇报日志,不阻止任何内容,可以改用Content-Security-Policy-Report-Only头 |
form-action | 定义针对提交的form到特定来源的加载策略。 |
referrer | 定义针对referrer的加载策略。 |
reflected-xss | 定义针对XSS过滤器使用策略。 |
CSP指令值
指令值 | 说明 |
---|---|
* |
允许加载任何内容 |
'none' |
不允许加载任何内容 |
'self' |
允许加载相同源的内容 |
www.koenli.com |
允许加载指定域名的资源 |
*.koenli.com |
允许加载koenli.com任何子域名的资源 |
https://koenli.com |
允许加载koenli.com的HTTPS资源 |
https: |
允许加载HTTPS资源 |
data: |
允许加载data:协议,例如:base64编码的图片 |
'unsafe-inline' |
允许加载inline资源,例如style属性、onclick、inline js、inline css等 |
'unsafe-eval' |
允许加载动态js代码,例如 eval() |
CSP例子
- 所有内容均来自网站的自己的域
1 | Content-Security-Policy: default-src 'self' |
- 所有内容都来自网站自己的域,还有其他子域(假如网站的地址是:koenli.com)
1 | Content-Security-Policy: default-src 'self' *.koenli.com |
- 网站接受任意域的图像,指定域(koenli.com)的音频、视频和多个指定域(koenlia.com、koenlib.com)的脚本
1 | Content-Security-Policy: default-src 'self';img-src *;media-src koenli.com;script-src koenlia.com koenlib.com |
Nginx配置Content-Security-Policy
在Nginx中可以通过在适当的位置(例如http
、server
、location
块)添加add_header
指令来设置Content-Security-Policy
响应头。以下是一个配置示例
1 | server { |
X-Frame-Options
X-Frame-Options响应头用来指示浏览器是否应该被允许在<frame>
、<iframe>
或者<object>
中显示页面内容。如果这个响应头缺失或者配置不正确,可能会导致点击劫持攻击,即攻击者可以通过嵌入一个看似安全的页面来欺骗用户。
响应头
- X-Frame-Options
语法
1 | X-Frame-Options: DENY |
说明
在Nginx中""
引号是必须要写的哦!
响应头值 | 说明 |
---|---|
DENY | 不允许被嵌入到任何<iframe> 或<frame> 中。 |
SAMEORIGIN | 只能被本站页面嵌入到<iframe> 或<frame> 中。 |
ALLOW-FROM uri | 只能被嵌入到指定域名的<iframe> 或<frame> 中。 |
Nginx配置X-Frame-Options
在Nginx中可以通过在适当的位置(例如http
、server
、location
块)添加add_header
指令来设置X-Frame-Options
响应头。以下是一个配置示例
1 | server { |
X-Content-Type-Options
X-Content-Type-Options用于控制浏览器是否应该尝试MIME类型嗅探。如果启用了X-Content-Type-Options,浏览器将遵循服务器提供的MIME类型,用于防止浏览器执行MIME类型错误的响应体(response body)。
如果在HTTP响应头中指定的Content-Type与实际响应体返回的MIME类型不一致,这种情况下浏览器可能会忽略响应头中指定的Content-Type,执行实际响应体的MIME类型,造成安全风险,而设置X-Content-Type-Options就是为了避免这种类型的安全风险。
响应头
- X-Content-Type-Options
语法
1 | X-Content-Type-Options: nosniff |
响应头值 | 说明 |
---|---|
nosniff | 当设置为nosniff时,浏览器将不会尝试根据内容进行MIME类型检测。即使服务器返回的内容与请求的MIME类型不匹配,浏览器也会按照服务器返回的MIME类型来处理响应 |
Nginx配置X-Frame-Options
在Nginx中可以通过在适当的位置(例如http
、server
、location
块)添加add_header
指令来设置X-Content-Type-Options
响应头。以下是一个配置示例
1 | http { |
Referrer-Policy
Referrer-Policy主要用于控制浏览器在发送跨域请求时如何处理HTTP Referrer信息
当用户在浏览器上点击一个链接时,会产生一个HTTP请求,用于获取新的页面内容,而在该请求的报头中,会包含一个Referer字段,用以指示该请求是从哪个页面跳转来的,常被用于分析用户来源等信息。但是也有成为用户的一个不安全因素,比如有些网站直接将SessionID或Token放在地址栏里传递,会原样不动地当作Referrer报头的内容传递给第三方网站。
所以就有了Referrer-Policy,用于过滤Referer报头内容,目前是一个候选标准,不过已经有部分浏览器支持该标准。具体的可查看这里。
使用场景
浏览器向服务器请求资源的时候,Referer字段的逻辑是这样的,用户在地址栏输入网址,或者选中浏览器书签,就不发送Referer字段。主要是以下三种场景,会发送Referer字段
- 用户点击网页上的链接
- 用户发送表单
- 网页加载静态资源,比图加载图片、脚本、样式
响应头
- Referrer-Policy
指令值
目前包含了以下几种指令值
1 | enum ReferrerPolicy { |
- 空字符串
若设为空串则默认按照浏览器的机制设置Referer字段的内容,默认情况下和no-referrer-when-downgrade设置的一样。
- no-referrer
不发送Referer字段
- no-referrer-when-downgrade (默认值)
如果从HTTPS网址链接到HTTP网址,不发送Referer字段,其他情况发送(包括HTTP网址链接到HTTP网址),这是浏览器的默认行为。
- same-origin
链接到同源网址(协议、域名、端口都相同)时才发送,否则不发送。
说明
https://koenli.com
链接到http://koenli.com
也属于跨域。
- origin
Referer字段一律只发送源信息(协议+域名+端口),不管是否跨域。
- strict-origin
如果从HTTPS网址链接到HTTP网址,不发送Referer字段,其他情况只发送源信息(协议+域名+端口)。
说明
与origin类似,但是不能降级。
- origin-when-cross-origin
当发请求给同源网站时,浏览器会在Referer字段中显示完整的URL信息,发给非同源网站时,则只显示源信息(协议+域名+端口)
- strict-origin-when-cross-origin
同源时,发送完整的Referer字段;跨域时,如果HTTPS网址链接到HTTP网址,不发送Referer字段,否则发送源信息(协议+域名+端口)。
说明
与origin-when-cross-origin类似,但不能降级。
- unsafe-url
浏览器总是会将完整的URL信息显示在Referer字段中,无论请求发给任何网站。
Nginx配置Referrer-Policy
在Nginx中可以通过在适当的位置(例如http
、server
、location
块)添加add_header
指令来设置Referrer-Policy
响应头。以下是一个配置示例
1 | server { |
Permissions-Policy
Permissions-Policy响应标头提供了一种可以在本页面或包含的iframe上启用或禁止浏览器特性的机制。它可以帮助网站防止恶意活动、提高隐私保护、减少跨站点攻击等。该头部允许指定要允许或禁止的功能类型和来源,包括网络检索、摄像头访问、麦克风访问、弹出窗口、全屏模式等。
语法
1 | Permissions-Policy: <directive> <allowlist> |
<allowlist>
一个来源列表,在括号中包含的以下一个或多个值,并用空格分隔:
*
:允许在当前文档和所有包含的内容(比如iframes)中使用本特性。'self'
:允许在当前文档中使用本特性,但在包含的内容(比如iframes)仍使用原值。'src'
:(只在iframe中允许) 只要在src中的URL和加载iframe用的URL相同,则本特性在iframe中允许,'none'
:从最上层到包含的内容都禁止本特性。<origin(s)>
: 在特定的源中允许,源URL以空格分割。*
或none
值只允许单独使用,而self
和src
值可以与多个源一起使用。
所有的特性都有一个如下的默认的allowlist
*
: 本特性默认在最上层和包含的内容中(iframes)允许。'self'
: 本特性默认在最上层允许,而包含的内容中(iframes)使用源地址相同设定。也就是说本特性在iframe中不允许跨域访问。'none'
: 本特性默认在最上层和包含的内容中(iframes)都禁止。
指令
指令 | 说明 |
---|---|
autoplay | 控制是否允许当前文档自动播放媒体。 |
camera | 控制是否允许当前文档使用视频输入设备。 |
document-domain | 控制是否允许当前文档设置 document.domain。 |
encrypted-media | 控制是否允许当前文档使用 Encrypted Media Extension (en-US) API(EME)。 |
fullscreen | 控制是否允许当前文档使用 Element.requestFullScreen()。 |
geolocation | 控制是否允许当前文档使用 Geolocation 接口。 |
microphone | 控制是否允许当前文档使用音频输入设备。 |
midi | 控制是否允许当前文档使用 Web MIDI API (en-US)。 |
payment | 控制是否允许当前文档使用 Payment Request API。 |
vr / xr | 控制是否允许当前文档使用 WebVR API。 |
示例
例如公司想要在应用中禁用震动和定位API,则可以在返回的response中传递以下定义权限策略的HTTP的标头信息:
1 | Permissions-Policy: vibrate 'none'; geolocation 'none' |
Nginx配置Permissions-Policy
在Nginx中可以通过在适当的位置(例如http
、server
、location
块)添加add_header
指令来设置Permissions-Policy
响应头。以下是一个配置示例
1 | server { |
结语
经过一系列的优化配置,再次使用https://securityheaders.com/进行检测后已经达到了A级别(最低F,最高A+)。当然HTTP响应头还有很多,并不只有这里提到的,更多的HTTP响应头可以参考https://developer.mozilla.org/zh-CN/docs/Web/HTTP