Skip to content

1,点击劫持

# 点击劫持(ClickJacking)是一种视觉上的欺骗手段。大概有两种方式,

# 一是攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在该页面上进行操作,此时用户将在不知情的情况下点击透明的iframe页面;

# 二是攻击者使用一张图片覆盖在网页,遮挡网页原有位置的含义;
# 点击劫持(ClickJacking)是一种视觉上的欺骗手段。大概有两种方式,

# 一是攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在该页面上进行操作,此时用户将在不知情的情况下点击透明的iframe页面;

# 二是攻击者使用一张图片覆盖在网页,遮挡网页原有位置的含义;
  • 解释:

2,X-Frame-Options

X-Frame-Options HTTP 响应头是微软提出来的一个HTTP响应头,主要用来给浏览器指示允许一个页面可否在 <frame>, <iframe> 或者 <object> 中展现的标记。网站可以使用此功能,来确保自己网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (ClickJacking{注1}) 的攻击

使用X-Frame-Options有三个值

# DENY # 表示该页面不允许在frame中展示,即使在相同域名的页面中嵌套也不允许 

# SAMEORIGIN # 表示该页面可以在相同域名页面的frame中展示 

# ALLOW-FROM url # 表示该页面可以在指定来源的frame中展示

如果设置为 DENY,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为SAMEORIGIN,那么页面就可以在同域名页面的 frame 中嵌套。

PS:目前发现这个HTTP响应头会带来的问题就是百度统计中的“热点追踪(页面点击图)”功能会失效,这也说明百度统计的“热点追踪(页面点击图)”使用的是 frame 嵌入引用网页的形式,这时候大家可以使用 X-Frame-Options 的ALLOW-FROM uri来指定百度统计域名为可 frame 嵌入域名即可。具体在Nginx里可以采用如下的方式添加响应头

比如:
add_header X-Frame-Options:ALLOW-FROM https://tongji.baidu.com;

add_header X-Frame-Options:SAMEORIGIN;

add_header X-Frame-Options ALLOWALL; #允许所有域名iframe

add_header Set-Cookie "Path=/; HttpOnly; Secure";
# DENY # 表示该页面不允许在frame中展示,即使在相同域名的页面中嵌套也不允许 

# SAMEORIGIN # 表示该页面可以在相同域名页面的frame中展示 

# ALLOW-FROM url # 表示该页面可以在指定来源的frame中展示

如果设置为 DENY,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为SAMEORIGIN,那么页面就可以在同域名页面的 frame 中嵌套。

PS:目前发现这个HTTP响应头会带来的问题就是百度统计中的“热点追踪(页面点击图)”功能会失效,这也说明百度统计的“热点追踪(页面点击图)”使用的是 frame 嵌入引用网页的形式,这时候大家可以使用 X-Frame-Options 的ALLOW-FROM uri来指定百度统计域名为可 frame 嵌入域名即可。具体在Nginx里可以采用如下的方式添加响应头

比如:
add_header X-Frame-Options:ALLOW-FROM https://tongji.baidu.com;

add_header X-Frame-Options:SAMEORIGIN;

add_header X-Frame-Options ALLOWALL; #允许所有域名iframe

add_header Set-Cookie "Path=/; HttpOnly; Secure";
X-Frame-Options
X-Frame-Options 响应头用于防范点击劫持(Click Jacking)。

响应头格式为:

x-frame-options: ${value}
可填入的 value 有三种:

allow-from ${domain} 不允许被指定域名以外的页面嵌入
sameorigin 不允许被站点自身域名以外的页面嵌入
deny 不允许被任何页面嵌入
由于嵌入的页面不会加载,这就减少了点击劫持的发生。

在 Nginx 中的配置:

add_header X-Frame-Options deny;

X-Content-Type-Options
互联网上的资源多种多样,在 web 浏览方面,一般浏览器会根据响应头的 Content-Type 字段分辨资源的类型。例如,”text/html” 表示 html 文件,”text/css” 表示 CSS 样式文件,”application/javascript” 表示 js 代码。但有时,会出现 Content-Type 未定义或无效值的资源,这时浏览器会调用 MIME-sniffing 来猜测该资源的类型。攻击者利用浏览器的这种猜测,例如可以让原本应解析为图片的请求被解析为恶意 JavaScript 脚本,被攻击者成功入侵。

为了防范这类攻击,需要禁用浏览器的资源类型猜测。

通过返回下面这个响应头:

X-Content-Type-Options: nosniff
其中,这个响应头的值只能是 nosniff。

在 Nginx 中的配置:

add_header X-Content-Type-Options nosniff;

X-XSS-Protection
顾名思义,这个响应头用于防范 XSS 攻击。

该响应头已具有广泛浏览器支持,并且主流浏览器基本默认开启 XSS 保护。倒是用这个头可以关闭它。虽然一般不建议这样做。

响应头格式为:

X-Xss-Protection: ${value}
可填入的值有三种:

0 禁用 XSS 保护
1 启用 XSS 保护
1; mode=block 启用 XSS 保护,并规定在检查到 XSS 攻击时停止页面渲染
在 Nginx 中的配置:

add_header X-Xss-Protection "1; mode=block" ;
X-Frame-Options
X-Frame-Options 响应头用于防范点击劫持(Click Jacking)。

响应头格式为:

x-frame-options: ${value}
可填入的 value 有三种:

allow-from ${domain} 不允许被指定域名以外的页面嵌入
sameorigin 不允许被站点自身域名以外的页面嵌入
deny 不允许被任何页面嵌入
由于嵌入的页面不会加载,这就减少了点击劫持的发生。

在 Nginx 中的配置:

add_header X-Frame-Options deny;

X-Content-Type-Options
互联网上的资源多种多样,在 web 浏览方面,一般浏览器会根据响应头的 Content-Type 字段分辨资源的类型。例如,”text/html” 表示 html 文件,”text/css” 表示 CSS 样式文件,”application/javascript” 表示 js 代码。但有时,会出现 Content-Type 未定义或无效值的资源,这时浏览器会调用 MIME-sniffing 来猜测该资源的类型。攻击者利用浏览器的这种猜测,例如可以让原本应解析为图片的请求被解析为恶意 JavaScript 脚本,被攻击者成功入侵。

为了防范这类攻击,需要禁用浏览器的资源类型猜测。

通过返回下面这个响应头:

X-Content-Type-Options: nosniff
其中,这个响应头的值只能是 nosniff。

在 Nginx 中的配置:

add_header X-Content-Type-Options nosniff;

X-XSS-Protection
顾名思义,这个响应头用于防范 XSS 攻击。

该响应头已具有广泛浏览器支持,并且主流浏览器基本默认开启 XSS 保护。倒是用这个头可以关闭它。虽然一般不建议这样做。

响应头格式为:

X-Xss-Protection: ${value}
可填入的值有三种:

0 禁用 XSS 保护
1 启用 XSS 保护
1; mode=block 启用 XSS 保护,并规定在检查到 XSS 攻击时停止页面渲染
在 Nginx 中的配置:

add_header X-Xss-Protection "1; mode=block" ;
  • nginx配置

允许单个域名iframe嵌套

add_header X-Frame-Options ALLOW-FROM http://xxx.com/;

允许多个域名iframe嵌套,注意这里是用逗号分隔

add_header X-Frame-Options "ALLOW-FROM http://xxx.com/,https://xxx.cn/";

3,X-Content-Type-Options

互联网上的资源有各种类型,通常浏览器会根据响应头的Content-Type字段来分辨它们的类型。例如:text/html代表html文档,image/png是PNG图片,text/css是CSS样式文档。然而,有些资源的Content-Type是错的或者未定义。这时,某些浏览器会启用MIME-sniffing来猜测该资源的类型,解析内容并执行。

例如,我们即使给一个html文档指定Content-Type为text/plain,在IE8-中这个文档依然会被当做html来解析。利用浏览器的这个特性,攻击者甚至可以让原本应该解析为图片的请求被解析为JavaScript。在Nginx里通过下面这个响应头可以禁用浏览器的类型猜测行为:


# X-Content-Type-Options HTTP 消息头相当于一个提示标志,被服务器用来提示客户端一定要遵循在 Content-Type 首部中对  MIME 类型 的设定,

# 而不能对其进行修改。这就禁用了客户端的 MIME 类型嗅探行为,换句话说,也就是意味着网站管理员确定自己的设置没有问题。

# X-Content-Type-Options响应头的缺失使得目标URL更易遭受跨站脚本攻击。

# add_header X-Content-Type-Options: nosniff;

这个响应头的值只能是nosniff
互联网上的资源有各种类型,通常浏览器会根据响应头的Content-Type字段来分辨它们的类型。例如:text/html代表html文档,image/png是PNG图片,text/css是CSS样式文档。然而,有些资源的Content-Type是错的或者未定义。这时,某些浏览器会启用MIME-sniffing来猜测该资源的类型,解析内容并执行。

例如,我们即使给一个html文档指定Content-Type为text/plain,在IE8-中这个文档依然会被当做html来解析。利用浏览器的这个特性,攻击者甚至可以让原本应该解析为图片的请求被解析为JavaScript。在Nginx里通过下面这个响应头可以禁用浏览器的类型猜测行为:


# X-Content-Type-Options HTTP 消息头相当于一个提示标志,被服务器用来提示客户端一定要遵循在 Content-Type 首部中对  MIME 类型 的设定,

# 而不能对其进行修改。这就禁用了客户端的 MIME 类型嗅探行为,换句话说,也就是意味着网站管理员确定自己的设置没有问题。

# X-Content-Type-Options响应头的缺失使得目标URL更易遭受跨站脚本攻击。

# add_header X-Content-Type-Options: nosniff;

这个响应头的值只能是nosniff

4,Content-Security-Policy

W3C 的 Content Security Policy,简称 CSP。顾名思义,这个规范与内容安全有关,主要是用来定义页面可以加载哪些资源,减少 XSS 的发生。

Chrome 扩展已经引入了 CSP,通过 manifest.json 中的 content_security_policy 字段来定义。一些现代浏览器也支持通过响应头来定义 CSP。下面我们主要介绍如何通过响应头来使用 CSP,Chrome 扩展中 CSP 的使用可以参考 Chrome 官方文档

# HTTP 响应头Content-Security-Policy允许站点管理者控制用户代理能够为指定的页面加载哪些资源。
# 除了少数例外情况,设置的政策主要涉及指定服务器的源和脚本结束点。

# Content-Security-Policy响应头的缺失使得目标URL更易遭受跨站脚本攻击。
# HTTP 响应头Content-Security-Policy允许站点管理者控制用户代理能够为指定的页面加载哪些资源。
# 除了少数例外情况,设置的政策主要涉及指定服务器的源和脚本结束点。

# Content-Security-Policy响应头的缺失使得目标URL更易遭受跨站脚本攻击。

4.1 如何使用

# 要使用 CSP,只需要服务端输出类似这样的响应头就行了:
Content-Security-Policy: default-src 'self'
  
# default-src 是 CSP 指令,多个指令之间用英文分号分割;'self' 是指令值,多个指令值用英文空格分割。目前,有这些 CSP 指令:
# 要使用 CSP,只需要服务端输出类似这样的响应头就行了:
Content-Security-Policy: default-src 'self'
  
# default-src 是 CSP 指令,多个指令之间用英文分号分割;'self' 是指令值,多个指令值用英文空格分割。目前,有这些 CSP 指令:
指令指令值示例说明
default-src'self' cnd.a.com定义针对所有类型(js、image、css、web font,ajax 请求,iframe,多媒体等)资源的默认加载策略,某类型资源如果没有单独定义策略,就使用默认的。
script-src'self' js.a.com定义针对 JavaScript 的加载策略。
style-src'self' css.a.com定义针对样式的加载策略。
img-src'self' img.a.com定义针对图片的加载策略。
connect-src'self'针对 AjaxWebSocket 等请求的加载策略。不允许的情况下,浏览器会模拟一个状态为 400 的响。
font-srcfont.a.com针对 WebFont 的加载策略。
object-src'self'针对 <object><embed><applet> 等标签引入的 flash 等插件的加载策略。
media-srcmedia.a.com针对 <audio><video> 等标签引入的 HTML 多媒体的加载策略。
frame-src'self'针对 frame 的加载策略。
sandboxallow-forms对请求的资源启用 sandbox(类似于 iframe 的 sandbox 属性)。
report-uri/report-uri告诉浏览器如果请求的资源不被策略允许时,往哪个地址提交日志信息。 特别的:如果想让浏览器只汇报日志,不阻止任何内容,可以改用 Content-Security-Policy-Report-Only 头。
指令值指令示例说明
img-src允许任何内容。
'none'img-src 'none'不允许任何内容。
'self'img-src 'self'允许来自相同来源的内容(相同的协议、域名和端口)。
data:img-src data:允许 data: 协议(如 base64 编码的图片)。
www.a.comimg-src img.a.com允许加载指定域名的资源。
.a.comimg-src .a.com允许加载 a.com 任何子域的资源。
https://img.comimg-src https://img.com允许加载 img.com 的 https 资源(协议需匹配)。
https: img-srchttps:允许加载 https 资源。
'unsafe-inline'script-src 'unsafe-inline'允许加载 inline 资源(例如常见的 style 属性,onclick,inline js 和 inline css 等等)。
'unsafe-eval'script-src 'unsafe-eval'允许加载动态 js 代码,例如 eval()

从上面的介绍可以看到,CSP 协议可以控制的内容非常多。而且如果不特别指定 'unsafe-inline' 时,页面上所有 inline 样式和脚本都不会执行;不特别指定 'unsafe-eval',页面上不允许使用 new Function,setTimeout,eval 等方式执行动态代码。在限制了页面资源来源之后,被 XSS 的风险确实小不少。

当然,仅仅依靠 CSP 来防范 XSS 是远远不够的,不支持全部浏览器是它的硬伤。不过,鉴于低廉的开发成本,加上也没什么坏处

5,Strict Transport Security

5.1 什么是Strict Transport Security

一个网站接受一个HTTP的请求,然后跳转到HTTPS,用户可能在开始跳转前,通过没有加密的方式和服务器对话,比如,用户输入http://foo.com或者直接foo.com。这样存在中间人攻击潜在威胁,跳转过程可能被恶意网站利用来直接接触用户信息,而不是原来的加密信息。网站通过HTTP Strict Transport Security通知浏览器,这个网站禁止使用HTTP方式加载,浏览器应该自动把所有尝试使用HTTP的请求自动替换为HTTPS请求

有的网站开启了https,但为了照顾用户的使用体验(因为用户总是很赖的,一般不会主动键入https,而是直接输入域名, 直接输入域名访问,默认就是http访问)同时也支持http访问,当用户http访问的时候,就会返回给用户一个302重定向,重定向到https的地址,然后后续的访问都使用https传输,这种通信模式看起来貌似没有问题,但细致分析,就会发现种通信模式也存在一个风险,那就是这个302重定向可能会被劫持篡改,如果被改成一个恶意的或者钓鱼的https站点,然后,你懂得,一旦落入钓鱼站点,数据还有安全可言吗?

对于篡改302的攻击,建议服务器开启HTTP Strict Transport Security功能,这个功能的含义是:

当用户已经安全的登录开启过htst功能的网站 (支持hsts功能的站点会在响应头中插入:Strict-Transport-Security) 之后,支持htst的浏览器(比如chrome. firefox)会自动将这个域名加入到HSTS列表,下次即使用户使用http访问这个网站,支持htst功能的浏览器就会自动发送https请求(前提是用户没有清空缓存,如果清空了缓存第一次访问还是明文,后续浏览器接收到服务器响应头中的Strict-Transport-Security,就会把域名加入到hsts缓存中,然后才会在发送请求前将http内部转换成https),而不是先发送http,然后重定向到https,这样就能避免中途的302重定向URL被篡改。进一步提高通信的安全性。

上面是我自己的理解,下面是owasp中文站点关于hsts的描述:

HSTS的作用是强制客户端(如浏览器)使用HTTPS与服务器创建连接。服务器开启HSTS的方法是,当客户端通过HTTPS发出请求时,在服务器返回的超文本传输协议响应头中包含Strict-Transport-Security字段。非加密传输时设置的HSTS字段无效。
比如,https://example.com/ 的响应头含有Strict-Transport-Security: max-age=31536000; includeSubDomains。这意味着两点:

在接下来的一年(即31536000秒)中,浏览器只要向example.com或其子域名发送HTTP请求时,必须采用HTTPS来发起连接。比如,用户点击超链接或在地址栏输入 http://www.example.com/ ,浏览器应当自动将 http 转写成 https,然后直接向 https://www.example.com/ 发送请求。

在接下来的一年中,如果 example.com 服务器发送的TLS证书无效,用户不能忽略浏览器警告继续访问网站。

HSTS可以用来抵御SSL剥离攻击。SSL剥离攻击是中间人攻击的一种,由Moxie Marlinspike于2009年发明。他在当年的黑帽大会上发表的题为“New Tricks For Defeating SSL In Practice”的演讲中将这种攻击方式公开。SSL剥离的实施方法是阻止浏览器与服务器创建HTTPS连接。它的前提是用户很少直接在地址栏输入https://,用户总是通过点击链接或3xx重定向,从HTTP页面进入HTTPS页面。所以攻击者可以在用户访问HTTP页面时替换所有https://开头的链接为http://,达到阻止HTTPS的目的。

HSTS可以很大程度上解决SSL剥离攻击,因为只要浏览器曾经与服务器创建过一次安全连接,之后浏览器会强制使用HTTPS,即使链接被换成了HTTP

另外,如果中间人使用自己的自签名证书来进行攻击,浏览器会给出警告,但是许多用户会忽略警告。HSTS解决了这一问题,一旦服务器发送了HSTS字段,用户将不再允许忽略警告。

0×03. Strict-Transport-Security的一些不足

用户首次访问某网站是不受HSTS保护的。这是因为首次访问时,浏览器还未收到HSTS,所以仍有可能通过明文HTTP来访问。解决这个不足目前有两种方案,一是浏览器预置HSTS域名列表,Google Chrome、Firefox、Internet Explorer和Spartan实现了这一方案。二是将HSTS信息加入到域名系统记录中。但这需要保证DNS的安全性,也就是需要部署域名系统安全扩展。截至2014年这一方案没有大规模部署。

由于HSTS会在一定时间后失效(有效期由max-age指定),所以浏览器是否强制HSTS策略取决于当前系统时间。部分操作系统经常通过网络时间协议更新系统时间,如Ubuntu每次连接网络时,OS X Lion每隔9分钟会自动连接时间服务器。攻击者可以通过伪造NTP信息,设置错误时间来绕过HSTS。解决方法是认证NTP信息,或者禁止NTP大幅度增减时间。比如Windows 8每7天更新一次时间,并且要求每次NTP设置的时间与当前时间不得超过15小时
有的网站开启了https,但为了照顾用户的使用体验(因为用户总是很赖的,一般不会主动键入https,而是直接输入域名, 直接输入域名访问,默认就是http访问)同时也支持http访问,当用户http访问的时候,就会返回给用户一个302重定向,重定向到https的地址,然后后续的访问都使用https传输,这种通信模式看起来貌似没有问题,但细致分析,就会发现种通信模式也存在一个风险,那就是这个302重定向可能会被劫持篡改,如果被改成一个恶意的或者钓鱼的https站点,然后,你懂得,一旦落入钓鱼站点,数据还有安全可言吗?

对于篡改302的攻击,建议服务器开启HTTP Strict Transport Security功能,这个功能的含义是:

当用户已经安全的登录开启过htst功能的网站 (支持hsts功能的站点会在响应头中插入:Strict-Transport-Security) 之后,支持htst的浏览器(比如chrome. firefox)会自动将这个域名加入到HSTS列表,下次即使用户使用http访问这个网站,支持htst功能的浏览器就会自动发送https请求(前提是用户没有清空缓存,如果清空了缓存第一次访问还是明文,后续浏览器接收到服务器响应头中的Strict-Transport-Security,就会把域名加入到hsts缓存中,然后才会在发送请求前将http内部转换成https),而不是先发送http,然后重定向到https,这样就能避免中途的302重定向URL被篡改。进一步提高通信的安全性。

上面是我自己的理解,下面是owasp中文站点关于hsts的描述:

HSTS的作用是强制客户端(如浏览器)使用HTTPS与服务器创建连接。服务器开启HSTS的方法是,当客户端通过HTTPS发出请求时,在服务器返回的超文本传输协议响应头中包含Strict-Transport-Security字段。非加密传输时设置的HSTS字段无效。
比如,https://example.com/ 的响应头含有Strict-Transport-Security: max-age=31536000; includeSubDomains。这意味着两点:

在接下来的一年(即31536000秒)中,浏览器只要向example.com或其子域名发送HTTP请求时,必须采用HTTPS来发起连接。比如,用户点击超链接或在地址栏输入 http://www.example.com/ ,浏览器应当自动将 http 转写成 https,然后直接向 https://www.example.com/ 发送请求。

在接下来的一年中,如果 example.com 服务器发送的TLS证书无效,用户不能忽略浏览器警告继续访问网站。

HSTS可以用来抵御SSL剥离攻击。SSL剥离攻击是中间人攻击的一种,由Moxie Marlinspike于2009年发明。他在当年的黑帽大会上发表的题为“New Tricks For Defeating SSL In Practice”的演讲中将这种攻击方式公开。SSL剥离的实施方法是阻止浏览器与服务器创建HTTPS连接。它的前提是用户很少直接在地址栏输入https://,用户总是通过点击链接或3xx重定向,从HTTP页面进入HTTPS页面。所以攻击者可以在用户访问HTTP页面时替换所有https://开头的链接为http://,达到阻止HTTPS的目的。

HSTS可以很大程度上解决SSL剥离攻击,因为只要浏览器曾经与服务器创建过一次安全连接,之后浏览器会强制使用HTTPS,即使链接被换成了HTTP

另外,如果中间人使用自己的自签名证书来进行攻击,浏览器会给出警告,但是许多用户会忽略警告。HSTS解决了这一问题,一旦服务器发送了HSTS字段,用户将不再允许忽略警告。

0×03. Strict-Transport-Security的一些不足

用户首次访问某网站是不受HSTS保护的。这是因为首次访问时,浏览器还未收到HSTS,所以仍有可能通过明文HTTP来访问。解决这个不足目前有两种方案,一是浏览器预置HSTS域名列表,Google Chrome、Firefox、Internet Explorer和Spartan实现了这一方案。二是将HSTS信息加入到域名系统记录中。但这需要保证DNS的安全性,也就是需要部署域名系统安全扩展。截至2014年这一方案没有大规模部署。

由于HSTS会在一定时间后失效(有效期由max-age指定),所以浏览器是否强制HSTS策略取决于当前系统时间。部分操作系统经常通过网络时间协议更新系统时间,如Ubuntu每次连接网络时,OS X Lion每隔9分钟会自动连接时间服务器。攻击者可以通过伪造NTP信息,设置错误时间来绕过HSTS。解决方法是认证NTP信息,或者禁止NTP大幅度增减时间。比如Windows 8每7天更新一次时间,并且要求每次NTP设置的时间与当前时间不得超过15小时

6, X-XSS-Protection

这个响应头是用来防范XSS的。最早我是在介绍IE8的文章里看到这个,现在主流浏览器都支持,并且默认都开启了XSS保护,用这个header可以关闭它。它有几种配置

#减少点击劫持
add_header X-Xss-Protection "1;mode=block" always;  #开启XSS过滤器

add_header X-Content-Type-Options 'nosniff';  #禁止嗅探文件类型

0:# 禁用XSS保护;
1:# 启用XSS保护;
1; # mode=block:启用XSS保护,并在检查到XSS攻击时,停止渲染页面(例如IE8中,检查到攻击时,整个页面会被一个#替换);

# HTTP X-XSS-Protection 响应头是 Internet Explorer,Chrome 和 Safari 的一个特性,
# 当检测到跨站脚本攻击 (XSS)时,浏览器将停止加载页面。

# X-XSS-Protection响应头的缺失使得目标URL更易遭受跨站脚本攻击。

# 浏览器提供的XSS保护机制并不完美,但是开启后仍然可以提升攻击难度,总之没有特别的理由,不要关闭它。
#减少点击劫持
add_header X-Xss-Protection "1;mode=block" always;  #开启XSS过滤器

add_header X-Content-Type-Options 'nosniff';  #禁止嗅探文件类型

0:# 禁用XSS保护;
1:# 启用XSS保护;
1; # mode=block:启用XSS保护,并在检查到XSS攻击时,停止渲染页面(例如IE8中,检查到攻击时,整个页面会被一个#替换);

# HTTP X-XSS-Protection 响应头是 Internet Explorer,Chrome 和 Safari 的一个特性,
# 当检测到跨站脚本攻击 (XSS)时,浏览器将停止加载页面。

# X-XSS-Protection响应头的缺失使得目标URL更易遭受跨站脚本攻击。

# 浏览器提供的XSS保护机制并不完美,但是开启后仍然可以提升攻击难度,总之没有特别的理由,不要关闭它。

CSP

什么是 XSS 攻击

跨站脚本(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及用户端脚本语言。

跨域脚本攻击(XSS 攻击)通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是 JavaScript,但实际上也可以包括 Java,VBScript,ActiveX,Flash 甚至是普通的 HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页、会话和 cookie 等各种内容。

为了防止它,要采取很多编程对策,成本较高。很多人发出呼声,能不能让浏览器自己禁止外部注入恶意脚本呢?这时,CSP 应运而生

什么是 CSP

CSP 定义了页面中哪些资源可以加载。

所以 CSP 的实质就是白名单,Web 端明确地告诉客户端,只有哪些外部资源可以加载可以执行,相当于提供一份白名单,“我的规则里没提到的全部拜拜,不给进来”。

因此 CSP 大大增强了网页的安全性。即使攻击者发现可趁之机,也没法注入脚本

CSP 的两种启用方式

一种是使用网页的 标签

<meta http-equiv="Content-Security-Policy" content="default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}">
<meta http-equiv="Content-Security-Policy" content="default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}">

一种是使用 HTTP 响应头

Content-Security-Policy: "default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}"
Content-Security-Policy: "default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}"

CSP 规则

http://note.youdao.com/noteshare?id=a6f38bb91d2cf0af9e78e3edb45e5322

CSP 在 Nginx 中的启用

add_header  Content-Security-Policy  "default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}";

add_header  Content-Security-Policy  "default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://www.w3.org https://avatars0.githubusercontent.com; font-src 'none'; media-src 'none'; object-src 'none'; connect-src 'self' https://github.com https://api.github.com; child-src 'none'" always;
add_header  Content-Security-Policy  "default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}";

add_header  Content-Security-Policy  "default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://www.w3.org https://avatars0.githubusercontent.com; font-src 'none'; media-src 'none'; object-src 'none'; connect-src 'self' https://github.com https://api.github.com; child-src 'none'" always;

将下面的Nginx配置文件代码放入到对应站点的.conf配置文件[server]里,然后重启Nginx即可生效

if ($request_method !~* GET|POST) { return 444; }
#使用444错误代码可以更加减轻服务器负载压力。
#防止SQL注入
if ($query_string ~* (\$|'|--|[+|(%20)]union[+|(%20)]|[+|(%20)]insert[+|(%20)]|[+|(%20)]drop[+|(%20)]|[+|(%20)]truncate[+|(%20)]|[+|(%20)]update[+|(%20)]|[+|(%20)]from[+|(%20)]|[+|(%20)]grant[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]where[+|(%20)]|[+|(%20)]select[+|(%20)]|[+|(%20)]and[+|(%20)]|[+|(%20)]or[+|(%20)]|[+|(%20)]count[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]chr[+|(%20)]|[+|(%20)]mid[+|(%20)]|[+|(%20)]like[+|(%20)]|[+|(%20)]iframe[+|(%20)]|[\<|%3c]script[\>|%3e]|javascript|alert|webscan|dbappsecurity|style|confirm\(|innerhtml|innertext)(.*)$) { return 555; }
 if ($uri ~* (/~).*) { return 501; }
 if ($uri ~* (\\x.)) { return 501; }
#防止SQL注入 
 if ($query_string ~* "[;'<>].*") { return 509; }
 if ($request_uri ~ " ") { return 509; }
 if ($request_uri ~ (\/\.+)) { return 509; }
 if ($request_uri ~ (\.+\/)) { return 509; }
 
 #if ($uri ~* (insert|select|delete|update|count|master|truncate|declare|exec|\*|\')(.*)$ ) { return 503; }
#防止SQL注入
 if ($request_uri ~* "(cost\()|(concat\()") { return 504; }
 if ($request_uri ~* "[+|(%20)]union[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]and[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]select[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]or[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]delete[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]update[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]insert[+|(%20)]") { return 504; }
 if ($query_string ~ "(<|%3C).*script.*(>|%3E)") { return 505; }
 if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { return 505; }
 if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { return 505; }
 if ($query_string ~ "proc/self/environ") { return 505; }
 if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") { return 505; }
 if ($query_string ~ "base64_(en|de)code\(.*\)") { return 505; }
 if ($query_string ~ "[a-zA-Z0-9_]=http://") { return 506; }
 if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") { return 506; }
 if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") { return 506; }
 if ($query_string ~ "b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)b") { return 507; }
 if ($query_string ~ "b(erections|hoodia|huronriveracres|impotence|levitra|libido)b") {return 507; }
 if ($query_string ~ "b(ambien|bluespill|cialis|cocaine|ejaculation|erectile)b") { return 507; }
 if ($query_string ~ "b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)b") { return 507; }
#这里大家根据自己情况添加删减上述判断参数,cURL、wget这类的屏蔽有点儿极端了,但要“宁可错杀一千,不可放过一个”。
 if ($http_user_agent ~* YisouSpider|ApacheBench|WebBench|Jmeter|JoeDog|Havij|GetRight|TurnitinBot|GrabNet|masscan|mail2000|github|wget|curl|Java|python) { return 508; }
#同上,大家根据自己站点实际情况来添加删减下面的屏蔽拦截参数。
 if ($http_user_agent ~* "Go-Ahead-Got-It") { return 508; }
 if ($http_user_agent ~* "GetWeb!") { return 508; }
 if ($http_user_agent ~* "Go!Zilla") { return 508; }
 if ($http_user_agent ~* "Download Demon") { return 508; }
 if ($http_user_agent ~* "Indy Library") { return 508; }
 if ($http_user_agent ~* "libwww-perl") { return 508; }
 if ($http_user_agent ~* "Nmap Scripting Engine") { return 508; }
 if ($http_user_agent ~* "~17ce.com") { return 508; }
 if ($http_user_agent ~* "WebBench*") { return 508; }
 if ($http_user_agent ~* "spider") { return 508; } #这个会影响国内某些搜索引擎爬虫,比如:搜狗
#拦截各恶意请求的UA,可以通过分析站点日志文件或者waf日志作为参考配置。
 if ($http_referer ~* 17ce.com) { return 509; }
#拦截17ce.com站点测速节点的请求,所以明月一直都说这些测速网站的数据仅供参考不能当真的。
 if ($http_referer ~* WebBench*") { return 509; }
#拦截WebBench或者类似压力测试工具,其他工具只需要更换名称即可
if ($request_method !~* GET|POST) { return 444; }
#使用444错误代码可以更加减轻服务器负载压力。
#防止SQL注入
if ($query_string ~* (\$|'|--|[+|(%20)]union[+|(%20)]|[+|(%20)]insert[+|(%20)]|[+|(%20)]drop[+|(%20)]|[+|(%20)]truncate[+|(%20)]|[+|(%20)]update[+|(%20)]|[+|(%20)]from[+|(%20)]|[+|(%20)]grant[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]where[+|(%20)]|[+|(%20)]select[+|(%20)]|[+|(%20)]and[+|(%20)]|[+|(%20)]or[+|(%20)]|[+|(%20)]count[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]chr[+|(%20)]|[+|(%20)]mid[+|(%20)]|[+|(%20)]like[+|(%20)]|[+|(%20)]iframe[+|(%20)]|[\<|%3c]script[\>|%3e]|javascript|alert|webscan|dbappsecurity|style|confirm\(|innerhtml|innertext)(.*)$) { return 555; }
 if ($uri ~* (/~).*) { return 501; }
 if ($uri ~* (\\x.)) { return 501; }
#防止SQL注入 
 if ($query_string ~* "[;'<>].*") { return 509; }
 if ($request_uri ~ " ") { return 509; }
 if ($request_uri ~ (\/\.+)) { return 509; }
 if ($request_uri ~ (\.+\/)) { return 509; }
 
 #if ($uri ~* (insert|select|delete|update|count|master|truncate|declare|exec|\*|\')(.*)$ ) { return 503; }
#防止SQL注入
 if ($request_uri ~* "(cost\()|(concat\()") { return 504; }
 if ($request_uri ~* "[+|(%20)]union[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]and[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]select[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]or[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]delete[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]update[+|(%20)]") { return 504; }
 if ($request_uri ~* "[+|(%20)]insert[+|(%20)]") { return 504; }
 if ($query_string ~ "(<|%3C).*script.*(>|%3E)") { return 505; }
 if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { return 505; }
 if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { return 505; }
 if ($query_string ~ "proc/self/environ") { return 505; }
 if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") { return 505; }
 if ($query_string ~ "base64_(en|de)code\(.*\)") { return 505; }
 if ($query_string ~ "[a-zA-Z0-9_]=http://") { return 506; }
 if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") { return 506; }
 if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") { return 506; }
 if ($query_string ~ "b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)b") { return 507; }
 if ($query_string ~ "b(erections|hoodia|huronriveracres|impotence|levitra|libido)b") {return 507; }
 if ($query_string ~ "b(ambien|bluespill|cialis|cocaine|ejaculation|erectile)b") { return 507; }
 if ($query_string ~ "b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)b") { return 507; }
#这里大家根据自己情况添加删减上述判断参数,cURL、wget这类的屏蔽有点儿极端了,但要“宁可错杀一千,不可放过一个”。
 if ($http_user_agent ~* YisouSpider|ApacheBench|WebBench|Jmeter|JoeDog|Havij|GetRight|TurnitinBot|GrabNet|masscan|mail2000|github|wget|curl|Java|python) { return 508; }
#同上,大家根据自己站点实际情况来添加删减下面的屏蔽拦截参数。
 if ($http_user_agent ~* "Go-Ahead-Got-It") { return 508; }
 if ($http_user_agent ~* "GetWeb!") { return 508; }
 if ($http_user_agent ~* "Go!Zilla") { return 508; }
 if ($http_user_agent ~* "Download Demon") { return 508; }
 if ($http_user_agent ~* "Indy Library") { return 508; }
 if ($http_user_agent ~* "libwww-perl") { return 508; }
 if ($http_user_agent ~* "Nmap Scripting Engine") { return 508; }
 if ($http_user_agent ~* "~17ce.com") { return 508; }
 if ($http_user_agent ~* "WebBench*") { return 508; }
 if ($http_user_agent ~* "spider") { return 508; } #这个会影响国内某些搜索引擎爬虫,比如:搜狗
#拦截各恶意请求的UA,可以通过分析站点日志文件或者waf日志作为参考配置。
 if ($http_referer ~* 17ce.com) { return 509; }
#拦截17ce.com站点测速节点的请求,所以明月一直都说这些测速网站的数据仅供参考不能当真的。
 if ($http_referer ~* WebBench*") { return 509; }
#拦截WebBench或者类似压力测试工具,其他工具只需要更换名称即可

案例

google+

# x-content-type-options: nosniff
# x-frame-options: SAMEORIGIN
# x-xss-protection: 1; mode=block
# x-content-type-options: nosniff
# x-frame-options: SAMEORIGIN
# x-xss-protection: 1; mode=block

Twitter

# strict-transport-security: max-age=631138519
# x-frame-options: SAMEORIGIN
# x-xss-protection: 1; mode=block
# strict-transport-security: max-age=631138519
# x-frame-options: SAMEORIGIN
# x-xss-protection: 1; mode=block

Paypal

# X-Frame-Options: SAMEORIGIN
# Strict-Transport-Security: max-age=14400
# X-Frame-Options: SAMEORIGIN
# Strict-Transport-Security: max-age=14400

facebook

strict-transport-security: max-age=60
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 0
content-security-policy: default-src *;script-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl 'unsafe-inline' 'unsafe-eval' https://*.akamaihd.net http://*.akamaihd.net;style-src * 'unsafe-inline';connect-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.spotilocal.com:* https://*.akamaihd.net ws://*.facebook.com:* http://*.akamaihd.net https://fb.scanandcleanlocal.com:*;
strict-transport-security: max-age=60
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 0
content-security-policy: default-src *;script-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl 'unsafe-inline' 'unsafe-eval' https://*.akamaihd.net http://*.akamaihd.net;style-src * 'unsafe-inline';connect-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.spotilocal.com:* https://*.akamaihd.net ws://*.facebook.com:* http://*.akamaihd.net https://fb.scanandcleanlocal.com:*;