| 导语 前端安全日益受到业内的关注,最近笔者和团队在和XSS漏洞对抗的这段时间,总结了部分常见的漏洞和修复方法,下面将结合具体业务对这些漏洞类型进行分析。并分享给大家。
前端安全日益受到业内的关注,前端安全指发生在浏览器端用户界面的各种安全问题。随着前端技术的发展,Web安全早已经从后端波及到前端,并且前端攻击的手段越来越刁钻,前端攻击可以说是“借刀杀人”,因为前端攻击的发生都是在用户的操作下进行的,这里的刀就是用户之手。目前排在前端攻击手段前三位的是:XSS、CSRF、界面伪造(钓鱼)。其中XSS攻击最频繁,XSS发生的多样性导致XSS的漏洞最容易被黑客发现并利用。
如果有漏洞,并被黑客利用的话,影响面是很广的。近期,笔者就在和XSS漏洞打交道。在和XSS漏洞对抗的这段时间,我们也总结了部分常见的漏洞和修复方法,下面将结合具体场景对这些漏洞类型进行分析。并分享给大家。
在前端获取本域名下的cookie方式,都是通过document.cookie获取原始cookie串,然后再进行分析和匹配。原始cookie串长成这样:
name1=value1; name2=value2; name3=value3; name4=value4
第一个name前面没有空格,最后一个value后面没有分号,其余中间的cookie都是name前面有空格,value后面有分号。所以导致匹配cookie串的时候千奇百怪。其中有这样一种匹配方式:
var reg1=new RegExp("(^|\\s)"+name+"=([^;]*)(;|$)");
设有cookie串:sCookie1为cat=1; dog=2; pig=3
设有cookie串:sCookie2为xss=2 cat=5; pig=4; cat=1
现在要获取cat的cookie值,那么reg1在匹配sCookie1的时候是正确的,能得到cat=1,但是在匹配sCookie2的时候,却得到的是cat=5。
分析原因不难看出,xss的cookie值为2 cat=5,2后面的\scat=5正好符合reg1的正则形式,漏洞在于name前面的正则不严谨,不应该是简单的^或者空格,更加严格的是;\s或者^,即空格前面必须有分号。
修复之后的正确匹配方式应该是:
var reg2=new RegExp("(^|;\\s*)"+name+"=([^;]*)(;|$)");
【后记】
正常情况下cookie值很少有形如a=b的形式,但是a=b的形式确实是可以成为cookie值的,所以,黑客可以通过篡改cookie值的方式来达到植入恶意代码的目的。
前端业务中,有一种页面是专门做跳转中转的,一般这种页面的url上会带一个目标跳转的链接参数,比如为sUrl,然后页面会做一些统一鉴权类的操作,当需要跳转的时候,直接就跳转到sUrl指定的地址。
首先科普一下,前端实现页面跳转不严格的来说有三种方法:
1)meta标签refresh属性实现
2)a标签href属性实现
3)脚本控制location对象
严格意义上,可以从脚本执行直接跳转而无需人工操作的有两种1)和3)
对于meta标签,下面这行代码将直接立刻跳转到qq首页
$("head").append("<meta http-equiv='refresh' content='0,url=http://www.qq.com'>");
对于location,可以直接把sUrl赋值给href,或者调用replace,assign方法均可实现跳转。
那么,sUrl跳转怎么实现xss攻击呢,我们知道浏览器的地址栏可以接受各种合法协议的地址,包括标准的http协议,ftp协议,https协议之外,还有诸多形如:thunder:// chrome:// javascript://等多种伪协议,其中javascript:后面的字符串可以直接当作javascript脚本被执行,非常危险。
下面直接给出处理这种sUrl跳转类逻辑的防XSS攻击的方法的步骤:
1)从url中获取sUrl的值
2)根据业务需要,写正则表达式判断url是否为标准的链接(http,https,ftp等)
3)如果是,则对sUrl进行统一的xss字符串的过滤
4)对过滤后的地址进行跳转。
参考处理demo如下:
var urlReg=new RegExp("^((http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\-\\@?^=%&/~\\+#])?)$",'i');
if(urlReg.test(decodeURIComponent(tool.request("s_url")))){//判断url合法性
window.location=tool.xss.filter(decodeURIComponent(tool.request("s_url")));
}else{
throw 'url非法';
}
【后记】
这个漏洞的原型来源于网站的登录跳转页:/ xx/login.html,这个页面是登录的跳转中转处理页面。影响面非常广泛,一旦黑客恶意引导登录,跳转地址上带有诸如javascipt:alert(docuemnt.cookie)的代码,用户端的cookie瞬间被获取。这是非常可怕的。
严格意义上说,在防XSS的背景下,写入到页面中的内容都需要经过xss函数的转义过滤后用jquery提供的html方法写入,或者直接用text方法写入,但是如果有一种值包含的html标签必须要用html写入,又需要防止xss过滤,该怎么办呢。
这种需求是有的,近期笔者就接触到关于获取的微信昵称中会包含emoji表情的情况,如果通过通用的xss过滤函数之后,emoji标签则显示不了,如果不通过xss过滤直接html写入,又存在昵称会被黑客恶意更改造成xss漏洞的风险。
奇怪的需求出来后,立马引起了我的注意,因为如果既要过滤xss,又要保留emoji的标签。必须要对昵称中的emoji和其它普通字符进行分离,分开处理之后再合并。
下面给出处理方案:
1)用正则匹配出昵称中所有的emoji标签,放入数组emojiArr
2)用一个不会被转义的字符替换所有的emoji标签,这里建议用固定前缀+时间戳的形式,如:{tag_时间戳}
3)对替换过的字符串进行统一的xss过滤
4)将过滤后的字符串中{tag_时间戳}用emoji标签数组emojiArr替换
5)替换后的字符串可以直接用html写入页面
笔者提供了一种方法,使用这个方法,开发人员可以如下使用即可将微信昵称安全完美得显示在页面中了:
var nickName=”哇哈哈<span class="emoji emoji1f48b"></span>”;
$("#nickname").html(tool.xss.filterWxNickName(nickName));
【后记】
在处理具体问题的时候,可以具体对待,类似处理微信昵称的场景应该有不少,但是思想不变,严格写好标签的匹配正则,然后分离标签和其它字符,再对其它字符进行转义,最后进行合并是通用的处理思想。
前端安全一直是我们追求的目标,我相信在以后的日子里我们还会遇到各种形形色色的前端威胁,但是只要我们有信心和能力与之做斗争,我们的安全网就会越来密,安全性就会越来越高。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。