前端安全-如何防⽌XSS攻击
前端安全
随着互联⽹的⾼速发展,信息安全问题已经成为企业关注的焦点之⼀,⽽前端⼜是引发企业项⽬安全问题的⾼危据点。在移动互联⽹时代,前端⼈员除了受到传统的XSS、CSRF攻击之外,还时常遇到⽹络劫持,⾮法的Hybrid API 等新型的⽹络安全问题。当然,随着浏览器的不断发展和优化,不断引⼊了CSP、Same-Site Cookies 等新的技术来解决问题。下⾯讨论⼀下前端⼈员如何防⽌XSS攻击。
XSS攻击的介绍
XSS(Cross-Site Scripting,跨域脚本攻击)攻击是最常见的 Web 攻击,是⼀种代码注⼊攻击。攻击者通过在⽬标⽹站上注⼊恶意脚本,使之在⽤户的浏览器上运⾏。利⽤这些恶意脚本,攻击者可获取⽤户的敏感信息如 Cookie、SessionID 等,进⽽危害数据安全。其重点是『跨域』和『客户端执⾏』。XSS攻击分类
1. 反射型XSS:常见情况是攻击者通过构造⼀个恶意链接的形式,诱导⽤户传播和打开,由于链接内所携带的参数会回显于页⾯中或作为页⾯的处理数
据源,最终造成XSS攻击。
2. 存储型XSS:与前者不同,存储型XSS是持久化的XSS攻击⽅式,通过⽤户输⼊个⼈信息或者发表⽂章的⽅式将恶意代码存储于服务器端,当其他⽤
户再次访问页⾯时触发,造成XSS攻击。
3. DOM based型XSS:同样也是利⽤对数据源不可靠,缺乏过滤,由于开发过程中,不可避免部分数据需要回填到DOM中,例如href、src、data-id等
标签属性,⽽通过构造特殊的字符串闭合原有的DOM标签,在其中注⼊script标签的⽅式造成攻击。
XSS的防范⼿段
针对XSS的防范,需要开发者养成意识,针对⽤户输⼊源的数据进⾏过滤,针对页⾯不可信任的数据源也要做好过滤,类似于响应头中的字段、url中的参数、refer等字段都是不可信的,并且结合其他⼿段和⽅法,让页⾯更加安全可控。
1. Htmlencode 转义特殊字符
在⼤部分的表单填写中,⽐如注册账号,会运⾏⽤户填写个⼈信息,包括昵称、邮箱、简介描述等,此类信息属于⾮富⽂本类型,最常⽤的处理⽅法是,对尖括号等特殊字符转义成实体字符进⾏存储,由于是⾮富⽂本信息,并且以标签内容形式展⽰,推荐使⽤ innerText 展⽰到页⾯中。
const htmlEncode = function (handleString){
return handleString
.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">")
.replace(/ /g," ")
.replace(/\'/g,"'")
.replace(/\"/g,""");
}
2. 引⼊XSS库针对⽤户输⼊源过滤,设置标签⽩名单
上⾯提到的都是⾮富⽂本的处理⽅法,然⽽在很多论坛、博客、商城中的页⾯排版,都是通过富⽂本的形式编辑的,即回显到页⾯中的就是⼀段HTML内容,不能再⽤纯⽂本的形式处理了。
⼤部分的富⽂本编辑器原理,都是提供⼀个具备contenteditable属性的dom元素,让⽤户对⼀段富⽂本进⾏编辑,其本质是对⼀段html进⾏处理,新增或删除样式等,最后通过回传富⽂本框中html的⽅式提供给开发者,意味着我们要允许⽤户填充⼀段html于我们的页⾯中。⽽获取到的html字符串我们不能直接进⾏简单的标签替换,否则会导致原有的样式丢失,最终展⽰在页⾯中的也不再是⼀篇排版精致的⽂章,因此我们要另寻他路。
⽆论是这份来⾃于富⽂本编辑器的html,还是来⾃于最终⽤户发起请求所获取到的html,都是不可信的,意味着在前端进⾏过滤是没有任何实际意义和价值的,因为攻击者可以轻易的伪造请求绕过限制,所以我们需要在我们的服务器端针对这段html进⾏过滤处理。针对html的标签⽩名单过滤,不同的语⾔有不同的库实现,这⾥主要介绍nodejs中常⽤的标签过滤库,nodejs中常⽤的库主要是xss和xss-filter,下⾯以xss库的使⽤为例:
// npm install xss
const xss = require("xss");
function handleXss(content) {
// 设置HTML过滤器的⽩名单
const options = {
whiteList: {
p: ['class', 'style'],
em: ['class', 'style'],
strong: ['class', 'style'],
br: ['class', 'style'],
u: ['class', 'style'],
s: ['class', 'style'],
blockquote: ['class', 'style'],
li: ['class', 'style'],
ol: ['class', 'style'],
ul: ['class', 'style'],
h1: ['class', 'style'],
h2: ['class', 'style'],
h3: ['class', 'style'],
h4: ['class', 'style'],
h5: ['class', 'style'],
h6: ['class', 'style'],
span: ['class', 'style'],
div: ['class', 'style'],
img: ['src', 'class', 'style', 'width'],
},
前端websocket怎么用};
// ⾃定义规则
const myxss = new xss.FilterXSS(options);
// 直接调⽤ myxss.process() 即可
content= myxss.process(content);
return content;
}
通过限定⽩名单,仅允许常见的⽂本展⽰标签以及图⽚img标签进⼊⽩名单,这部分会再过滤后被保留,并且标签内的class和style属性也会被保留;其他属性和诸如script、iframe等标签都会被直接过滤掉。
const html = `
<p class="test" onclick="alert('xss');" ab="cd">123</p>
<img src="/xxx.png" onerror="alert('xss')" />
<12a></12a>
<script></script>
`;
console.log(handleXss(html));
/*
<p class="test">123</p>
<img src="/xxx.png" />
<12a></12a>
<script></script>
*/
普通的标签可以直接通过绑定onclick的⽅式攻击,即便是img、video等资源加载标签,也可以通过onload、onerror等事件注⼊脚本,可见针对标签内属性的过滤也是不可或缺的。
然⽽本以为这样已⾜够,但是即使是只开放了class和style属性开放了,也是不安全的,关键在于style属性,如果任由⽤户⾃定义的话,可以通过style属性实现:点击劫持(将元素铺满整个界⾯)、加载外域图⽚、脚本注⼊甚⾄可以给⽂章设置⼀些花⾥胡哨的动画:
<div >
点击劫持的元素,阻⽌页⾯其他操作</div>
<div >
借助style标签注⼊脚本,⼤部分xss过滤库会帮我们过滤这部分脚本</div>
<div >
偷偷加载其他⽹站的⼩H图,绕过过滤和审核</div>
可见style属性也不容忽视,因此我们需要在option参数中额外为style属性设置⽩名单,确保style属性安全可控:
// ...
css: {
whiteList: {
color: true,
'background-color': true,
},
},
// ...
其次为了确保不加载⾮本域名下的图⽚资源,我们也可以再这⼀层做⼀些针对img标签的过滤:
// ...
stripIgnoreTag: true,
onTagAttr: (tag:string, name:string, value:string, isWhiteAttr:boolean) => {
// 判断img下的src属性如果⾮本域名下返回空
if (isWhiteAttr && tag === 'img' && name === 'src' && !checkLegal(value))
{
return '#';
}
},
// ...
3. cookie 设置HttpOnly,配合token或验证码防范
针对信息源的过滤,针对不可信数据源的过滤,已经能达到初步的效果,但这远远不够,毕竟没有绝对的安全。
由于⼤部分攻击者会想要获取到⽤户的cookie去做别的坏事,所以我们需要在http的响应头set-cookie时设置httpOnly,让浏览器知道不能通过kie的⽅式获取到cookie内容。
<('/', (req, res) => {
kies.isVisit) {
console.kies)
res.send('欢迎再次光临')
} else {
res.send('欢迎初次光临')
}
})
虽然避免了攻击者直接获取到cookie,但是攻击者仍然可以页⾯内发起别的请求,直接篡改⽤户的信息,因此需要我们配合token或者验证码的形式,防⽌攻击者直接通过脚本的⽅式篡改⽤户个⼈信息。⽽这个token类似于CSRF中我们所需要的token,不过如果攻击者仔细研究了代码,并且知道的token在页⾯中的来源,也是可以直接获取到token的,因此,相⽐之下验证码安全性更⾼。
4. 设置CSP安全策略
除了针对数据源的严格过滤以外,CSP安全策略的限制也是主要的XSS防范⼿段之⼀,通过在页⾯中设置允许加载的资源的来源,来严格限制页⾯可加载的脚本以及图⽚等资源,防⽌外部的脚本攻击后注⼊其他脚本以及内容。
CSP,内容安全策略,是⼀种基于内容的声明式⽹络应⽤程序机制,对缓解内容注⼊漏洞的危害⾮常有效。通过⼀系列指令告诉客户端(如浏览器)被保护资源(如页⾯)内只允许加载和执⾏指令集中限定的内容,类似⽩名单机制,不满⾜限定条件的资源和内容将被客户端阻断或不被执⾏。可以通过两种⽅式设置CSP,⼀种是meta标签,⼀种是HTTP响应头Content-Security-Policy:
指令及其说明:
default-src 定义资源默认加载策略
connect-src 定义Ajax、 WebSocket等加载策略
font-src 定义Font 加载策略
frame- src 定义Frame加载策略
img-src 定义图⽚加载策略
media- src 定义<audio>、 <video> 等引⽤资源加载策略
object-src 定义 <applet>、 <embed>、 <object> 等引⽤资源加载策略
script-src 定义JS加载策略
style- src 定义CSS加载策略
接下来,以meta标签设置CSP为例,我们可以如下设置,以此来限制对⽩名单外资源加载:
<meta http-equiv="Content-Security-Policy" content=
"script-src 'self' *.qq *.cdn-go;
img-src 'self' *.cdn-go *.gtimg data:;
style-src 'unsafe-inline' *.cdn-go;
media-src 'none';
child-src *.qq">
参考:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论