XSS

针对页面完全可控的参数,禁止直接渲染在页面上,比如v-html之类的方法直接使用,还有用于元素的属性等地方

禁止在localStorage中存储敏感信息

检查方法:在前端代码中搜索localStorage关键字,分析代码中是否通过localStorage写入敏感数据。

使用postMessage方法实现跨域

HTML5增加了window.postMessage(message,targetOrigin,[transfer])方法,该方法可以实现跨域通信。通常对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https)、端口号(443为https的默认值)以及主机(两个页面的Document.domain设置为相同的值)时,这两个脚本才能相互通信。window.postMessage()方法提供了一种受控机制来规避此限制。

作为发送方:
当您使用postMessage将数据发送到其他窗口时,targetOrigin始终指定为精确的目标地址,不应使用通配符关键字(*)。恶意网站可以在您不知情的情况下更改窗口的位置,因此它可以拦截使用postMessage发送的数据。
错误的示例:

// 发送方为https://example1.com页面的窗口,接收方为https://example2.com页面的窗口
var myWindow = document.getElementById('myIFrame'.contentWindow);
//该消息可以发送到任何可以接受消息的窗口,不止https://example2.com页面的窗口
myWindow.postMessage(message,"*");

正确的示例:

var myWindow = document.getElementById('myIFrame'.contentWindow);
myWindow.postMessage(message,"https://example2.com");//该消息只能发送给https://example2.com的窗口

测试方法:
在前端代码中搜索postMessage,若第二个参数指定接收方的域名,则不存在安全问题,反之则存在问题。

作为接收方:
如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。任何窗口都可以向任何其他窗口发送消息,因此不能保证未知发送方不会发送恶意消息。
错误示例如下:

// https://example2.com 页面的窗口接收数据
window.addEventListener("message", function( event ) {
/*对接收到的数据做处理*/
//这里没有对接收到的数据的来源做任何验证,直接就对数据做了处理,这很可能会引发跨站脚本攻击
}, false );

正确的示例:

window.addEventListener("message",receiveMessage,false);
//函数receiveMessage实现:
function receiveMessage(event){
    // 先通过event.origin判断数据的来源是否可信
    if(event.origin == "https://example1.com"){
        /* 对接收到的数据做处理*/
    }
}

特别说明:

if ('addEventListener' in document) {
    //非IE浏览器
    window.addEventListener('message', this.handler, false);
} else if ('attachEvent' in document) {
    //IE浏览器
    window.attachEvent('onmessage', this.handler);
}

通常前端代码中会针对是否为IE浏览器有不同的处理分支。
测试方法:
在前端代码搜索若存在从其他网站接收message的场景,测试时在前段代码中搜索addEventListener,第二个参数是对接收的数据做处理的函数,需要对数据的来源进行校验,反之则存在问题。
刷新关键字

if ('addEventListener' in document) {
    window.addEventListener('message', this.handler, false);
} else if ('attachEvent' in document) {
    window.attachEvent('onmessage', this.handler);
}

HTTP响应头的安全设置

HTTP消息头是指,在超文本传输协议(Hypertext Transfer Protocol ,HTTP)的请求和响应消息中,协议头部分的那些组件。HTTP消息头用来准确描述正在获取的资源、服务器或者客户端的行为,定义了HTTP事务中的具体操作参数。由于HTTP是一个可扩展的协议,各浏览器厂商都率先推出了有效的头部,来阻止漏洞利用或提高利用漏洞的难度。
Content-Security-Policy安全配置
浏览器Content-Security-Policy是一种以可信白名单作机制,来限制网站是否可以包含某些来源内容,可以用来缓解XSS注入漏洞的危害。CSP规定的网站只接受指定的请求资源,默认配置下不允许执行内联代码(<script>块内容,内联事件,内联样式),以及禁止执行eval()、newFunction()、setTimeout([string], ...)和setInterval([string], ...)
两种方法可以启用CSP,一种是通过HTTP 响应头配置Content-Security-Policy的值

另一种是通过网页的<meta>标签。
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
上面代码中,CSP 做了如下配置:

脚本(script-src):只信任当前域名
<object>标签(object-src):不信任任何URL,即不加载任何资源
样式表(style-src):只信任cdn.example.org和third-party.org
框架(child-src):必须使用HTTPS协议加载
其他资源:没有限制

启用后,不符合CSP 的外部资源就会被阻止加载。
Chrome 的报错信息。

Firefox 的报错信息。

指令就是csp中用来定义策略的基本单位,我们可以使用单个或者多个指令来组合作用,功能防护我们的网站.

指令名 demo 说明
default-src 'self' cdn.example.com 默认策略,其他没写的指令都会服从default-src 的规则
script-src 'self' js.example.com 定义js文件的过滤策略
style-src 'self' css.example.com 定义css文件的过滤策略
img-src 'self' img.example.com 定义图片文件的过滤策略
connect-src 'self' 定义请求连接文件的过滤策略
font-src font.example.com 定义字体文件的过滤策略
object-src 'self' 定义页面插件的过滤策略,如 <object>, <embed> 或者<applet>等元素
media-src media.example.com 定义媒体的过滤策略,如 HTML6的 <audio>, <video>等元素
frame-src 'self' 定义加载子frmae的策略
sandbox allow-forms allow-scripts 沙盒模式,会阻止页面弹窗/js执行等,你可以通过添加allow-forms allow-same-origin allow-scripts allow-popups, allow-modals, allow-orientation-lock, allow-pointer-lock, allow-presentation, allow-popups-to-escape-sandbox, and allow-top-navigation 策略来放开相应的操作
report-uri /some-report-uri
指令值
所有以-src结尾的指令都可以用一下的值来定义过滤规则,多个规则之间可以用空格来隔开
demo 说明
---- ---- ----
* img-src * 允许任意地址的url,但是不包括 blob: filesystem: schemes.
'none' object-src 'none' 所有地址的咨询都不允许加载
'self' script-src 'self' 同源策略,即允许同域名同端口下,同协议下的请求
data: img-src 'self' data: 允许通过data来请求咨询 (比如用Base64 编码过的图片).
domain.example.com img-src domain.example.com 允许特性的域名请求资源
*.example.com img-src *.example.com 允许从 example.com下的任意子域名加载资源
https://cdn.com img-src https://cdn.com 仅仅允许通过https协议来从指定域名下加载资源
https: img-src https: 只允许通过https协议加载资源
'unsafe-inline' script-src 'unsafe-inline' 允许行内代码执行
'unsafe-eval' script-src 'unsafe-eval' 允许不安全的动态代码执行,比如 JavaScript的 eval()方法

示例
default-src 'self';   
只允许同源下的资源
 
script-src 'self';     
只允许同源下的js
 
script-src 'self' www.google-analytics.com ajax.googleapis.com;
允许同源以及两个地址下的js加载
 
default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';
多个资源时,后面的会覆盖前面的
 
服务器端配置
Nginx
在 server {}对象块中添加如下代码
add_header Content-Security-Policy "default-src 'self';";
IIS
web.config:中添加

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Content-Security-Policy" value="default-src 'self';" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

以下指令不使用default-src的值作为指令。如果不对其进行设置,则等同于允许加载任何内容:base-uri、form-action、frame-ancestors、plugin-types、report-uri、sandbox

请确保在一条指令中列出所需的特定类型的全部资源。如果您编写类似script-src https://host1.com; script-src https://host2.com 的指令,则第二条指令将被忽略。如下指令可正确地将这两个来源指定为有效来源:
script-src https://host1.com https://host2.com
当前CSP包含CSPv1和CSPv2,可以通过如下链接查看浏览器的支持情况:

CSPv1:http://caniuse.com/#feat=contentsecuritypolicy
CSPv2:http://caniuse.com/#feat=contentsecuritypolicy2

在测试时首先查看任意业务请求响应的CSP的值,然后再检查CSP配置的值是否安全:
1、通常建议CSP配置为default-src 'self',这样CSP指令加载的源都来自网站自己的域,此时是安全;
2、如果业务需要定制CSP的指令,需要逐一确认配置的指令值是否安全:建议通过白名单配置业务需要加载资源的最小集,谨慎使用“*”,否则可能加载到恶意网站的资源;使用'unsafe-inline' 和'unsafe-eval' 都是不安全的,存在XSS注入攻击风险,因此严禁使用这两个值。请参考https://developers.google.com/web/fundamentals/security/csp?hl=zh-CN进行代码修改,这样可以不用设置这两个危险的指令也能使业务正常运行。
在测试时可以将当前使用的CSP的值到https://csp-evaluator.withgoogle.com/进行在线检查,也会提供对应的修复建议:

检查时选择当前主流的浏览器支持的CSP Version2。

X-XSS-Protection安全配置
在测试时首先查看任意业务请求响应的X-XSS-Protection的值,然后再检查X-XSS-Protection配置的值是否安全。X-XSS-Protection提供XSS攻击保护,可能的赋值如下:
X-XSS-Protection: 0:过滤不生效(不安全的配置,严禁使用)
X-XSS-Protection: 1:过滤生效+净化(安全的配置)
X-XSS-Protection: 1; mode=block:过滤生效+阻止显示页面(安全的配置)
X-XSS-Protection: 1; report=http://localhost:1234/report:过滤生效+净化+上报(Chrome)(安全的配置)
特殊说明:当响应未设置header时,浏览器默认进行XSS防御,此时也是安全的。
Chrome示例,服务器Node.js代码样例:

未设置header时,浏览器阻止显示,默认进行了XSS防御:

设置X-XSS-Protection: 0

设置X-XSS-Protection: 1

设置X-XSS-Protection: 1; mode=block

设置X-XSS-Protection: 1; report=http://localhost:1234/report

X-Frame-Options安全配置
在测试时首先查看任意业务请求响应的X-Frame-Options的值,然后再检查X-Frame-Options配置的值是否安全。通常在iframe标签中,可以允许创建包含另外一个文档的内联框架,比如指向外部的一个URL地址。设置该安全头部用于防御点击劫持攻击。可能的取值如下:
X-Frame-Options: deny:禁止显示frame内的页面(即使是同一网站内的页面)
X-Frame-Options: sameorigin:拒绝加载如果不符合同源策略
X-Frame-Options: allow-from <DOMAIN>:允许在frame内显示来自指定URI的页面请关注与frame-ancestors的区别。
Chrome示例:
服务器Node.js代码样例:

未设置X-Frame-Options:成功内嵌了一个外部网页:

X-Frame-Options: deny:都无法内嵌外部网页:

X-Frame-Options: sameorigin:同源加载,非同源拒绝:

X-Frame-Options: allow-from http://localhost:4321设置与本身加载的domain冲突,Google Chrome直接忽略。

Microsoft Edge也同样忽略。可见Chrome和Edge同时对比了iframe的src domain和主网页domain。而在Firefox中,对Domain的对比,是当前主网页的domain和设置的allow domain对比,一致加载,不一致不加载。

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。通过下面这个响应头可以禁用浏览器的类型猜测行为:
X-Content-Type-Options: nosniff
示例:
设置content-type为text/plain,尝试执行JS脚本。

未设置X-Content-Type-Options:

设置X-Content-Type-Options:nosniff

Set-Cookie安全配置
建议的安全设置的cookie值如下:
Set-Cookie: <key>=<value>; Expires=<expiryDate>; Secure; HttpOnly; SameSite=strict
在Set-Cookie中添加如下三个值,提高安全性:
Secure:标示只通过https传递cookies,可用于防御中间人攻击
HttpOnly:cookies设置该标签之后,将不能通过javascript访问到,xss攻击将不能直接读取cookies
SameSite:用于防御CSRF攻击,设置该属性后,cookies不能被发送到不同网站

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

Strict-Transport-Security: max-age=<expire-time>
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
Strict-Transport-Security: max-age=<expire-time>; preload

指令:
max-age=<expire-time>:
设置在浏览器收到这个请求后的<expire-time>秒的时间内凡是访问这个域名下的请求都使用HTTPS请求。每次浏览器接收到Strict-Transport-Security头,它都会更新这个网站的过期时间,所以网站可以刷新这些信息,防止过期发生。
includeSubDomains(可选):
如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。
preload(可选):
预加载HSTS,谷歌维护的一个HSTS 预加载服务。如果按照指示成功提交域名后,浏览器将会永不使用非安全的方式连接到域名。虽然该服务是由谷歌提供的,但所有浏览器都有使用这份列表的意向(或者已经在用了)。但是,这不是HSTS 标准的一部分,也不该被当作正式的内容。Chrome&Chromium的HSTS预加载列表可以此查询:
https://www.chromium.org/hsts。通常建议暂不需要配置。

示例:
现在和未来的所有子域名会自动使用HTTPS 连接长达一年。同时阻止了只能通过HTTP 访问的内容。具体指令如下:
Strict-Transport-Security: max-age=31536000; includeSubDomains

Content-Type安全设置
Content-Type未设置或设置为text/html;charset=UTF-8或text/plain存在问题,可造成XSS。
对每个接口响应都必须设置响应头Content-Type,且不能设置为text/html或text/plain(如果需要设置为text/html或text/plain,需要单独根据测试指导部分的表格试验结果,评审是否会造成xss问题)。

posted @ 2021-03-29 08:00  木-鱼  阅读(248)  评论(0编辑  收藏  举报