XSS Filter
0x01 前言及TOC
最近在看 XSS 的相关内容,也有很多需要注意的东西。在平时的开发及设计当中,不可避免的会遇到XSS,于是就有了设计一些filter的想法,以前也在phithon的github上看到过Python的XSS filter,毕竟自己动手实现一个对于理解XSS,以及过滤的相关事情是很有帮助的。因此设计一些简单的filter,以备自己使用,并且这些filter是不安全的,不要放在生产环境,毕竟没有经过一些专业的检测,以及自己的JavaScript和XSS水平有待提高。以及以后可能还会写一些如何attack 这个filter的文章。
TOC:
- 基础的filter
- Python filter设计
- Java filter设计
- PHP filter设计
- 系统层面filter
- 后记
- 相关paper
0x02 基础的filter
首先需要过滤<>”()/script等字符(“>_<script123”),在PHP里可以使用preg_replace函数去过滤,并且通过htmlspecialchars函数转换为HTML实体编码。即:
1 | function safe_replace($content){ |
这里可以采用zicai的XSS-learn代码进行实验。
java可以使用:
1 | string = string.replaceAll("<", "<"); |
当有了过滤以后,测试<>”(号时,发现<>被转义成<
和>
,而”(等的并没有转义,当时怀疑是被实体编码了。当看到实际代码时,发现是字符串正则替换,后来一想,如果是类似于httpspecialchars那种的实体编码的话,引号也应该转义才对。当时还想着怎么绕过实体编码转义,于是又有了一个问题,关于java里的escapeHtml的底层实现是怎样的?以及实体编码是怎样的过程,似乎这个有点偏离主题了,这个完了再思考去写一篇总结编码的文章。
而在Python里可以使用
1 | import cgi |
以上都是一些正则过滤和escape编码的手段,当然不会过滤掉所有的XSS,仅可以防御一些小白。
还是会有人去寻找其他的可控点,或者想办法去绕过过滤。
当然这可以过滤**’;alert(String.fromCharCode(88,83,83))**这种的攻击向量么,如果可控点在JavaScript代码里呢,或者javascript伪协议,例如
1 | <img src="javascript:alert('xss');"> |
以及如果使用黑名单去过滤javascript伪协议的XSS,可以使用一些空格或者回车Tab等的绕过。即:
1 | <img src="javas |
如何去过滤这种的呢?
将换行符换成\n,将回车符换成\r,将制表符换成\t,空格可以遍历去除。
当过滤完这种的以后呢,又会出现一些大小写混淆或者十进制十六进制编码或者注释的示例:
1 | <img src="JavaScRiPt:alert('xss');"> |
面对这些,如果过滤/*&#javascript\;
,不如采取一些白名单的形式,仅允许执行特定形式的,去正则匹配结果。例如:仅允许<img src="http://">
这种的。
可以构造正则语句:”/^((http|ftp|https)://)?[\w-.]+(/[\w-]+)*/?$/“
如果单纯地过滤一些常见的<script>
标签或者onerror、onResume
等事件,还是可能会利用<link>
引入一个内容为如下的CSS进行hack。
1 | @import 'javascript:alert("XSS")'; |
当然还是要记得去判断变量类型,数字型的直接判断是否是数字,字符型的限定一些长度,并且不能有特殊字符,还有不能有拆分跨站法(疯狂的跨站之行)的出现。
如果一直针对绕过的方法,去不断过滤,未免有点麻烦,应该设计一个统一的filter,加强防御。
#####0x03 Python filter设计
一些用户的输入都是不可信的。
基础的过滤就得使用一些函数或者开源库:
1 | //基础的过滤 |
富文本过滤类的一种思路:
1.解析HTML节点
2.过滤白名单标签,删除不在白名单的标签,并且判断属性及属性值。
以及一些框架的处理策略:
tornado:
Tornado框架原则上所有输出在模板里的变量都会经过”HTML实体化”,并且官方文档也给出了一篇文章的链接,说明了仅过滤&, <, >, “, 和 ‘ 这些字符是不够的。
tornado都会自动执行xhtml_escape方法,将<, >, “, ‘, 和&进行了转义。
但是也需要针对特殊情况去过滤,关注一些输出在JavaScript代码的地方,进行特定形式的转义、正则匹配。
0x04 PHP filter设计
《XSS跨站脚本与防御》的第242页给出了一个通用的过滤XSS的函数,贴到了gist。
PHP在处理$_GET
、$_POST
、$_REQUEST
等变量时需过滤一次。
需要使用一些filter_var(),filter_input()函数来进行构造一些规则,进行一些模式的匹配,过滤。
网上的一个防止基本的XSS函数:
1 | function transform_HTML($string, $length = null) { |
从代码可以看到,期间过滤的一些空格,Unicode转码的问题,一些十进制十六进制的编码,并且限定了长度,进行了HTML实体编码,针对基础的XSS问题足够了。可以设计一个函数,获取GET、POST、REQUEST参数的时候,可以进行XSS的防护。
以及可以使用一些类似于HTML Purifier,或者一些富文本过滤类。
0x05 Java filter设计
Java Web方面,通过过滤一些Request请求,在GET或者POST请求层面进行过滤。
Java里面本来就有一个Filter类,继承这个Filter类,然后可以通过构造一个XSSRequestWrapper,过滤一些HttpServletRequest,配置好Web.xml,使这个继承后的Filter类全局有效,进行自动的anti一些xss,过滤掉所有请求里的恶意脚本。
在XSSRequestWrapper这个类里,需要重写一些getParameterValues(), getParameter() 和 getHeader()方法,期间实现一些过滤xss的函数,通过一些HTML实体编码的手段,以及正则匹配替换掉一些关键词,或者直接replaceAll去替换。
Web.xml的配置方法:
1 | <!-- XSS过滤器 --> |
也可以使用一些类似于Lucy-XSS : XssFilter, XssPreventer的模块去处理。
0x06 系统层面filter
这里的系统层面,侧重于WAF方面。
WAF可以是硬件层面,也可以是软件层面,ngx_lua_waf就提供了一种基于nginx_lua的思路。
通常会定义一些过滤规则,就像下面这样的正则匹配规则:
1 | \.\./ |
当然有些WAF还是联网获取这些规则的,它们采用的一些正则表达式匹配的方法,比较容易被绕过的,也有人提出了主动防御的概念。
0x07 后记
当学习地渐渐深入的时候,会越来越发现其的神奇,不断的过滤,不断的绕过,以及还有二哥和长短短的一些猥琐的思路,并且也有很多人教导学习XSS时候,一定要注意JavaScript基础,毕竟好的一名跨站师,xsser都是JavaScript很厉害。
当然防御XSS,不只有建立filter,也需要一些HttpOnly,Noscript,WAF,CSP的配合,更需要加强安全意识。
以后探索的方向:
自动化挖掘XSS漏洞,自动化防御,CVE里的XSS,以及总结一些好的XSS思路,新型XSS,自动化利用框架,浏览器Filter策略,防御XSS,机器学习等。。。
0x08 相关paper及资料
- 给开发者的终极XSS备忘录
- python-xss-filter
- site:freebuf.com xss
- Wooyun Drops
- owasp-esapi-python
XSS Filter