0

1相关背景

过滤器是处于客户端与服务器资源文件之间的一道网,在访问资源文件之前,通过一系列的过滤器对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改。也可以对响应进行过滤,拦截或修改响应。通过Filter技术对request、JSP、静态资源等进行拦截,从而实现一些安全需求,例如常见的权限访问控制、SQL注入和XSS敏感内容过滤、响应信息编码处理,设置响应头等。但是如果相关的过滤器存在缺陷,那么可能导致相关的安全防护无效,进而攻击者可以绕过过滤器对Web应用进行攻击。

0 2Filter简单工作原理

过 滤 器在web程序启动时进行加载,发送的request请求先到过滤器,过滤器判断我们的request内容是否符合设定的规则,符合再将request请求发送到web资源,当web资源处理完后,将response响应再丢给过滤器,最后过滤器将对应的响应信息给到用户。

java 设置不拦截的静态路径_双引号

01Filter常见安全设计问题 结合实际代码审计遇到的场景,常见问题如下:


获取数据的方式:

既然要对request中的参数内容进行检测,那么首先肯定是要获取到对应的内容了,常见过滤器获取request请求内容的方式如下,通过HttpServletRequest中的getParameter()或者getParameterNames()方法进行获取参数内容:

java 设置不拦截的静态路径_双引号_02

或者使用HttpServletRequestWrapper重写request请求参数的function(这里是重写了getParameterNames()):

java 设置不拦截的静态路径_js事件_03

但是使用request.getParameterNames()方法并不能覆盖所有的数据提交方式,同理,request.getParameter()亦然。

在request中主要是根据Content-type进行判断提交的方式,服务器根据其值将body体里的内容恢复成相应的数据结构。常见的Content-type类型如下:


  • application/x-www-form-urlencoded(最常见的POST提交方式,以键值对的方式进行传输,例如key=value)
  • application/json(JSON提交方式)
  • text/xml(XML提交方式)
  • multipart/form-data(文件上传表单,上传文件功能会用到)

使用上面常见过滤器中的

request.getParameterNames()&&request.getParameter()方法明显是无法覆盖上面全部类型的,那么如果只是简单的配置安全过滤器,那么可能会存在过滤器失效或者防护不足的问题。

JSON格式支持比常见的键值对复杂得多的结构化数据,所以在实际的开发场景里会经常用到。但是

request.getParameterNames()&&request.getParameter()方法明显是无法获取并解析application/json这种提交方式的。

举例说明,利用上述方式搭建Web环境,SQL注入也是常见的安全漏洞,预编译是很好解决该漏洞的方案,但是类似Orderby排序、动态表名等场景明显无法进行预编译,那么过滤器过滤敏感输入就是很好的一种解决方案了。

正常情况下是可以拦截application/x-www-form-urlencoded这种常见的提交方式并进行SQL注入过滤检测的:

java 设置不拦截的静态路径_js事件_04

但是如果某个业务接口是JSON提交的话,上述的过滤器明显无法获取到request提交的内容并进行安全检查,这里使用报错注入成功避开过滤器获得了当前数据库的user:

java 设置不拦截的静态路径_filter 不过滤静态文件_05

再者,对于multipart/form-data这种数据类型上述过滤器明显也是无法获取request提交内容的。那么如果此时存在类似批量Excel导入(例如批量新建用户)的业务功能点的话,那么上述过滤器也无法进行安全防护,例如excel导入的内容输出在页面上并未进行编码转译,xss过滤器由于无法获取到multipart/form-data类型的数据,导致存储型XSS。

当然了,即使我们的requet请求均以application/x-www-form-urlencoded类型进行传统的key-value方式提交,可能由于一些框架的特性,也会存在对应的绕过风险。

以Java常见的SpringMVC为例:

简单来说,服务器层面获取到前端请求后,接下来SpringMVC会收到服务器传来的request请求,此时若请求为上传POST型,SpringMVC会继续调用相关的解析器对其进行解析处理。以下是搭建的相关环境:

正常情况下的数据包如下,查询业务,查询tkswifty成功返回对应的员工信息:

java 设置不拦截的静态路径_双引号_06

尝试以multipart方式提交(上传POST型),同样的服务器接收到参数后,相关框架也进行了解析并完成了查询业务:

java 设置不拦截的静态路径_双引号_07

前面也提到了。对于multipart/form-data这种数据类型上述使用request.getParameterNames()&&request.getParameter()方法进行内容获取的过滤器明显是对写入的恶意poc无法进行检测处理的。

  • 过滤的规则内容:

过滤器中的安全规则检查,本质就是黑名单/白名单。不符合安全规则的则进行拦截。

以xss的过滤器为例,因为xss在实际开发场景中比较杂乱,因为在view层写入的位置很多,而且各个场景下的编码转译方式都不一样,很多时候无法兼顾每一个位置,所以更多的会选用过滤器进行XSS的防护。但是如果过滤器内容存在缺陷的话,攻击者可以绕过过滤器对Web应用进行攻击。

在github上找了一个现成的过滤器,进行相关的安全审计,该过滤器主要是对用户的输入进行检查,如果命中相关的正则便将对应的内容替换为空,例如输入

java 设置不拦截的静态路径_服务器_08

相关的规则乍一看还是很全的,过滤的内容包括相关的协议、标签、js函数以及相关的js事件。

以下面场景为例,分析上面的过滤器内容,尝试绕过进行xss攻击:

java 设置不拦截的静态路径_服务器_09

该场景的xss攻击的思路如下:


  1. 闭合双引号然后结合js事件(例如onclick)进行触发;
  2. 闭合双引号然后尝试新建标签进行触发。

以下针对上面两种思路进行尝试:

首先尝试闭合双引号然后写入js事件进行触发,输入tkswifty”οnclick=”alert(1),其中alert被过滤了:

java 设置不拦截的静态路径_双引号_10

查看过滤器规则,把window对象以及alert过滤了:

java 设置不拦截的静态路径_js事件_11

但是不妨碍使用prompt进行触发,如果要进一步尝试利用的话,也可以通过这种方式来调用windows对象:window['alert'](window['document']['cookie']):

java 设置不拦截的静态路径_filter 不过滤静态文件_12

而且可以发现,虽然规则里过滤了相关的js事件(例如onclick、oncopy),但是这种场景下似乎并没有生效,规则如下:

java 设置不拦截的静态路径_双引号_13

可以看到正则是这类的输入会直接过滤掉,对于非

java 设置不拦截的静态路径_js事件_14

所以针对闭合双引号然后结合js事件的场景该过滤器的过滤内容存在缺陷,可简单绕过。

然后是闭合双引号然后尝试新建标签进行触发,根据前面的分析,直接写入

java 设置不拦截的静态路径_js事件_15

正确的顺序应该是解码过滤器应该在xss过滤器之前,一次解码后,在xss过滤器中通过request.getParameter()得到的就是

再比如现在很多app都是加密传输的,很多情况下会在过滤器进行数据包的解密,然后再提交给对应的Controller进行业务处理,如果对应的类似xss过滤器是在解密过滤器之前的话,也是无法起到防护效果的。

0 3总结

过滤器作为安全开发中常用的方法,并不是简单的复制黏贴就可以达到对应的效果的,其内容规则、顺序、获取数据的方式等细节都是值得推敲考究的。

java 设置不拦截的静态路径_双引号_16