我本人一直关注“知识”与“知识运用”之间的区别,我曾经举过一个例子说:“知识”与“知识运用”就如牛郎星与织女星,感觉二者之间似乎关系密切,实则相隔甚远!我在初学平面几何时,经常会这么想: 两条线平行则永远不会相交,这不是废话吗! 三角形两边之和当然大于第三边了!…… 在实际运用当中,我经常是需要用它的时候想不起来或者用错了它们。
我的文章《输入验证可避免一半以上的应用安全攻击》,对于此文我相信是IT业界的人都能看明白,但是对于一个企业来说,它的价值万金,有多少人可以体味呢?
对于XSS问题的系统性解决方案上也是一样的。许多公司已经90%以上的程度解决了XSS问题,但是依然存在那10%的风险,风险在哪里,我想我会一步一步给大家分享清楚。XSS问题是全球性普遍性问题,没有深度的探索就不可能有彻底的解决方案,没有灵丹妙药,只有正确的方法!
好,进入正题。
基于HTTP协议的B/S(browser/server)架构的Web应用程序,有它的特殊性,它结构松散、多标签语言相互嵌入以及服务端与客户端使用了相互关联实现上却完全不同等等复杂的技术,以至于给基于HTTP协议的Web应用程序埋下了诸多潜在的安全问题,XSS问题就是其中之一。
我们使用C/C++/Javascript,大家都清楚,如果我想在字符串当中表达字符【”】,很自然的就会想到转义【\”】,想在字符串当中表达【\】,就得使用转义(与本文中所说“编码”概念相同)形式【\\】,在HTML文档当中也是这样,但是大家有没有想过这几个问题:
1. 这个转义后的字符串是为谁而转义的?
2. 这个转义后的字符串是何时被还原成转义前的字符串的?
3. 有没有可能还原之后的字符被重新放回到代码中而忽略了转义?
答案:
1. 为解释器(或编译器,为了简单,后面只称解释器)而转义,字符串被解释后在内存当中的字符串等同于转义前字符串
2. 通常解释器是在读取语言(C/C++/Javascript…)字符串后进行本地语言转换前进行还原的
3. 有,在基于HTML架构的前端(浏览器端)应用程序,尤为常见。比如: var myString=”<script>alert(\”jiayzhan\”)<\/script>”; 这个myString想表达的字符串是
<script>alert(“jiayzhan”)</script>,如果被document.write(myString)重新写到DOM里,结果是什么呢? 或者也可能会直接赋值给某一HTML节点的innerHTML/outerHTML属性,这里的问题就复杂了,二次赋值之后,你的程序没那么聪明,它不会主动替你转义一下再赋值,你可能会说:这不就是DOM Base XSS吗? 你想的简单了,对于我来说是DOM Based、反射式的还是存储式的,这种分类意义不大,解决方案都是一样,这就是高级别抽象后的解决方案的统一。这个问题较复杂,我们循序渐进的来了解它,您先知道有这么回事儿。有心的读者可能会问:C/C++/Java会有这种情形吗? 答案是:当然有,有一些软件为了兼容性等诸多因素考虑,会在编译时依据条件不同动态生成新的代码然后再进行编译,此时你该如何是好?这不是本文讨论的重点,为了叙述的完整性,提一下有这么回事儿就行。本文的重点是Web应用当中的XSS问题。
铺垫的差不多了,我们来一起看一段以下的HTML的document:
- <html>
- <body>
- <h1>jiayzhan's item</h1>
- <a ID="jiayzhan" onclick="alert('jiayzhan\'s onclick')" href="http://www.jiayzhan.org" ">jiayzhan's link</a>
- </body>
- <script>
- location.replace("jiayzhan's URL")
- </script>
- </html>
【说明】带有字符串【jiayzhan】的一整串,您需要将它们理解为类似于这样的JSP代码:<%=request.getParameter(“jiayzhan”);%>
下面一步一步来说浏览器是如何解码(反转义)的,我就用字符串本身作为位置标识来解释:
1. 位置:jiayzhan’s item, 浏览器在解析这个位置的字符串时,无论如何,会对其进行一次HTML解码,(HTML编码、解码,请参考)
2. 位置:jiayzhan\’s onclick,无论如何,浏览器会对其进行:1) 先做HTML解码 2)再做JS解码
3. 位置: http://www.jiayzhan.org,无论如何,浏览器会对其进行:URL解码
4. 位置:jiayzhan’s URL, 无论如何,浏览器会对此位置字符串进行:1)先JavaScript解码 (JS编解码请参考) 2)后URL解码
以上只是一维与二维组合的情形,实际当中还会有三维以上的解码组合,特别是大量使用Web2.0技术的网站。您理解了吗? 如果您真的理解了,请分析一下以下代码段中的变量<%=request.getParameter(“jiyazhan_url”)%>,浏览器如何做解码?如果你真的理解了浏览器的解码过程,你何尝不知道你在解决XSS问题时的编码过程? 请在评论中回复,我会及时与您讨论:
<a href=”javascript:backToHome(<%=request.getParameter(“jiyazhan_url”)%>)” >click jiayzhan</a>
说明:backToHome是一个javascript函数
在这里先不说它的解码过程,提示一下它是一个三维解码过程,供读者讨论吧。
写到这里,我想点睛一下我上文所述的”许多公司已经90%以上的程度解决了XSS问题”而不是100%的原因了。本ID曾给某一知名公司报了一个XSS问题,其存在XSS问题的地方因为是一个三维的解码语法环境,应用安全与开发人员许久也没有找到合理的解决方案,最终此公司删除了那个有XSS问题的功能点。不点名了,如果有幸遇到此公司的应用安全人员,这篇文章读明白了,问题应该就好解决了。还是那句话:知识与知识运用相隔甚远,我无法保证您可以正确运用它。
既然知道浏览器是如何解码的了,我们该如何做编码的事应该水到渠成了,不过依我的经验看,许多专业做XSS问题fix的解决方案的安全人员依然存在难以转过这个弯的情况。下篇文章我将举几个具体的例子来说明如何利用解码原理用来彻底解决XSS问题的编码问题,以及在涉及到多重解码的环境如果考虑维数不足所带来的安全隐患是什么(透露一下:如果编码维数考虑不足的可能结果是:
1). 其实等于没解决,只是漏洞发现的难度大了一些而已,对于我来说都一样
2). 改变了用户的输入,比如:用户想找一个【“】,结果系统帮它找的是【\"】或【%22】或【"】......)。
今天先这样吧,纯技术文章,不知道有多少同行会耐心的阅读它。