之前公司的安全组扫出了我们官网的几个安全漏洞。安全问题对很多前端来说都是只听过,没见过。这次遇到了真实对漏洞,可以做个记录。
存储型XSS漏洞
XSS,跨站脚本攻击。存储型XSS攻击,即攻击代码被当成文本(如帖子)提交保存到服务器,其他用户打开这段文本的时候,代码就会在其他用户的浏览器里执行。
场景:一个坏人在论坛发布帖子 内容如下:
大家好,第一次在这个论坛发帖,现在我要植入一段代码:<img src=x onerror=alert(1)>
如果论坛没有对帖子的内容做转义处理,直接发布出去。 其他用户点击这个帖子,页面就会插入这个图片标签。由于图片的src
异常,图片加载失败,就会触发onerror
里的alert。
如果onerror
里的内容不是一个简单的alert
,而是一段盗取用户cookies的代码呢?那么就会对用户对账户造成威胁。
防御措施
对< > / 符号做escape
转义即可,escape
可以把所有ASCII 之外的所有字符转换为 %xx 或 %uxxxx(x表示十六进制的数字)的转义序列。
延伸:vue 中 v-html 指令的合理使用
用过 vue 的同学都知道,v-html 的作用是可以把填入 v-html 里的值转化为 html 代码,所以 v-html
可能会成为攻击者利用的漏洞,如果把用户提交的内容使用 v-html
渲染,就可能会把用户输入的内容变成可执行的代码,形成 XSS 攻击。
反射型XSS漏洞
反射型漏洞:攻击者通过特定的方式来诱惑受害者去访问一个包含恶意代码的URL。
场景还是坏人在论坛发帖,坏人在帖子里贴一个URL,其他用户访问这个URL,使URL上的代码在用户浏览器里被执行。
可能有人会问,在帖子里附带链接不是正常现象吗,用户点击第三方链接导致被攻击跟我有什么关系?
那么,如果用户点击的就是官方链接而触发了XSS攻击呢?
场景:这个发生场景现在来看有点古老了,但大部分网站可能仍会使用的跨域策略:JSONP。
简单描述JSONP的流程:前端使用<script>
标签请求后端资源,后端返回的资源会被一个函数包裹,类似:
callback({
a: 1,
b: 2
});
而前端会提前在页面定义好这个callback
函数,例如:
// 请求到达页面,触发 callback 函数,将资源挂到window上
function callback(res) {
window.res = res;
}
而通常后台返回的函数名并不会固定返回callback
,因为可能会调用到页面其他叫callback
的函数,所以,前端在请求的时候,都会在链接后带一个参数,告诉后台,返回的函数名应该叫什么,例如:
前端请求地址:https://xxxxx/giftjson?jsoncallback=mycallback
后台返回结果:
// jsoncallback传的参数是什么,返回的函数名就是什么
mycallback({
a: 1,
b: 2
});
可以看到,请求地址上的jsoncallback
参数是什么,后台返回的函数名就是什么。看到这句话是不是隐隐感觉到不对劲?如果jsoncallback
参数是一段代码呢?
假设,坏人发现了斗鱼直播的一个接口有这个漏洞,在斗鱼论坛发帖:
斗鱼出了个活动啦,大家点击这个链接可以免费抽奖,这个是斗鱼官方链接大家放心点:
https://www.douyu.com/getUserInfo?jsoncallback=<img+src=x+onerror=alert(1)>
其他用户发现这个确实是斗鱼的官方链接就点了进去,结果就运行了jsoncallback
里的代码。
防御措施
个攻击其实还需要一点机缘巧合,比如把返回头的Content-Type
设置成了application/javascript
或者text/html
,就会导致字符被当作代码运行。所以防止反射型攻击的方法就是将返回头的Content-Type
设置为application/json;
即可。
CSRF 攻击
CSRF,跨站点请求伪造。即攻击者在他自己的网站调用你的接口,达到修改你的网站数据的目的。
场景:用户在斗鱼论坛设置了“记住我的登录状态”,于是 douyu.com
这个域名下保存了用户的登录cookies。攻击者注意到斗鱼修改用户资料的接口douyu.com/updateUserInfo
有CSRF漏洞,于是他伪造了一个斗鱼论坛网站,并做了一个表单:
<html>
<body>
<form id="csrf" action="douyu.com/updateUserInfo" method="POST">
<input type="hidden" name="gender" value="2" />
<input type="hidden" name="hometown" value="1234" />
<input type="hidden" name="birthday" value="2020-06-11" />
<input type="hidden" name="nick_name" value="1234" />
<input type="hidden" name="st" value="123" />
</form>
</body>
<script type="text/javascript">
function autoSubmit() {
document.getElementById("csrf").submit();
}
autoSubmit()
</script>
</html>
这个表单会提交到douyu.com/updateUserInfo
接口,由于用户的浏览器保存了登录的cookies,请求发送出去的时候,用户的登录态也会带出去,斗鱼验证登录态后,确认了是用户本人操作,允许了本次修改。
我们可以发现,通过CSRF漏洞,攻击者伪造了用户的登录态,使修改用户资料的操作成功了。如果本次操作不是修改用户操作,而是转账等危害用户资产安全的操作呢?
防御措施
由此可见,涉及资料修改的操作,仅验证用户登录态是不够的。还需要其他的验证手段:
初级防御措施:判断请求的Referer
头
请求中的Referer
头用于判断该请求是在哪个页面的基础上发出去的,比如a.com
请求了一张图片douyu.com/1.jpg
,那么图片的Referer
头就为:Referer: a.com
。
上面的攻击场景中,服务器可以判断请求的Referer
头,判断该请求是否是官方网站douyu.com
发出的,如果不是,则说明是第三方调用,禁止修改。
但是问题是,请求的请求头是可以修改的,攻击者只要将请求的Referer
头手动修改为douyu.com
,就绕过了这层防御。
进阶防御措施:
-
token校验
每个修改资料的请求,都必须携带一个token,而这个token只能在官方网站下生成,提交修改操作的时候,校验这个token是否正确,只有正确才允许修改资料。
这种验证又叫做“加盐”验证。在表单中混入一个做校验的表单项,用来给服务器做安全校验。 -
cookies设置Samesite
设置保存登录态的 cookies 只能在同一个域名的页面下才会随着请求一起发送。这样可以保证cookies不会被第三方使用。但是也多了一个束缚是登录态不能被其他我们受信任的域名共享。
比如很多单点登录的实现(即如果你在taobao.com登录了,你访问tmall.com的时候,会发现也是登录着的)就是基于 cookies 共享,可能就会收到影响。
网友评论