1 XSS攻击
XSS攻击,指黑客通过“HTML”注入篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击行为。
接下来通过一个简单的示例展示XSS攻击的一种方式,服务器使用nodejs
假设我的web服务器上提供了这样一个网页,读取url中用户提交的名字,然后输出到页面中
var server = http
.createServer(function(req, res) {
if (req.url != "/favicon.ico") {
var r = url.parse(req.url);
var obj = querystring.parse(r.query);
let name = obj.name;
let html = `<div>服务器将用户输入的数据直接写到页面中</div>
<div>大家好,我是${name}</div>`;
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.write(html);
res.end();
}
})
.listen(52052);
console.log("server is listening at port 52052");
正常的时候,我通过这样一个URL转到网页http://localhost:52052?name=bright,如下图
但是加入我输入这样一个URL呢?http://localhost:52052?name=<script>alert(‘this is a xss attack’)</script>
Chrome会检测url中的恶意代码,但是edge不会,edge下结果如下图:
可以看到用这个url可以在网页中注入我的HTML代码,并执行了其中的脚本。但是到目前为止,都只是我自己在自娱自乐,怎么作为传说中的黑客去攻击别人呢?假如我把这个链接用邮件或者其他方式发给了你,然后你又出于好奇打开了这个链接,那么在你的网页上就会执行我注入的脚本代码。想象一下这是一个银行的网站的话,那么我可以编写脚本,窃取你的银行账户信息(脚本中通过ajax模拟你的操作查询服务器,并将数据发给我的服务器),如果网站没有认证机制那么我甚至可以直接转账给其他银行账户。
反射型xss
上面的示例是反射型xss,反射型xss其实就是服务器把用户的数据直接输出给浏览器,在攻击的时候往往要构建一个url,然后诱使攻击目标点击这个url。
存储型xss
存储型xss会将客户的输入存储在服务器端,最典型的就是博客系统,假如我在博客的富文本编辑器中插入了<script>标签,其中加载了我编写的脚本代码,那么所有浏览我这篇博客的同学的浏览器中都会执行我的脚本。如果能在被攻击者的浏览器中执行我的代码,那我的代码就可以模拟被攻击者的大部分操作,控制被攻击者的账户,在其浑然不觉的情况下窃取数据,删除数据,甚至将这篇有问题的博客推荐给其好友并感染其好友(可以想象感染可能是1传10,10传100的指数型增长)。
当然这只是分析,像CSDN的markdown编辑器中script标签,img标签都是被过滤的,这是xss攻击的防御方面的,待会儿我们会着重分析。
DOM Based XSS
前两种都是服务器向客户端直接输出有问题的脚本。但是有时候并不是这么直接。
有时候我们会向DOM中通过innerHTML这种形式来动态改变dom,这种情况下,假如innerHTML中插入的数据是来自其他用户的输入,比如从服务器拿了一个数据,然后又将这个数据在JavaScript中写到页面中,这样就可能导致xss攻击。
XSS攻击的防御
xss攻击本质上是一种HTML注入,即攻击者想法设法的向服务器提供的网页中嵌入能够执行自己的脚本的html代码。
(1) HttpOnly
服务器在set-cookie的时候指定一个httponly的参数,这样可以保证cookie不会被脚本读取到,只能用于http请求。
Set-Cookie:token=123443243; expires= ${new Date()}; max-age=120; domain=localhost;httponly
(2) 输入检查
在用户输入的时候检查,判断用户的输入是不是可能导致xss攻击,过滤掉特殊字符比如<、>等,但是需要视情况而定,一律暴力过滤可能会影响原有功能。如果用户的输入并不会写入html文档中,那么就不会导致xss攻击。
在富文本编辑器中,过滤掉危险的标签比如script, base,JavaScript伪协议等,同时事件的触发也要严格禁止。可以用htmlparser分析得到的html代码,看是不是会执行恶意代码。使用标签的白名单而不是黑名单。
(3)输出检查
将特殊字符编码成html实体