XSS、SQL注入
背景
由于某些客户现场以及我们公司自身的要求,产品上线之前都会有一轮的安全扫描,用AppScan等这类工具扫一扫,最近就处理了几个安全扫描的问题,虽说处理的比较原始但是还是需要记录一下,你晓得哇,因为比较折磨人。
工作原理
什么交XSS、SQL注入网上一大堆我就不出丑了哈,要解决这块问题那就先得搞清楚AppScan这类软件的工作原理。
AppScan 工作原理小结如下:
- 通过爬行配置的整个 Web 应用,了解其结构找到接口等信息
- 根据分析的结果,发送修改后的Request 进行攻击尝试(扫描规则库模拟XSS、SQL注入等操作)
- 最后分析 Respone ,验证是否符合预期是否存在安全漏洞
所以由此看出处理XSS、SQL注入等问题只能在第二个和第三个环节出手。
处理姿势
处理这类问题我所知道的通常就3种姿势:
拦截
触发了这类校验直接拦截掉并提示不让其做任何操作,简单粗暴但是不人性化。经常让人很懵逼。
替换
把可触发这类校验的关键字全部替换为其它字符或者转换为字符串等。这种容易破坏原有的表达。
加密
这是种欺骗扫描软件的方式,直接前后端约定加密方式,对所有的输入进行统一加密,后端再统一解密,这样扫描软件识别不了任何关键字。我同事就这样干过,虽然说性能上会有一点问题但是好在不用动任何代码。嗯,这种只能说骚操作。
实操
最后和架构师定的方式是通过filter+正则这种最原始最简单的方式来做,我们这是toB的运维系统所以让大家失望了没上高大上的安全策略。
输入流
需要先搞清楚为什么需要处理输入流,因为 reqeust.getInputStream 方法只能读取一次。我们可以大概捋一下是咋回事。
我们需要输入流所以需要调用reqest.getInputStream(),getInputStream返回值为ServletInputStream,所以我们先看看ServletInputStream。
1 | public abstract class ServletInputStream extends InputStream { |
然后知道是继承自InputStream,所以我们先看InputStream,注意read和reset方法。
read方法告诉我们会从输入流一直读取下一个字节、如果以达到末尾侧返回-1。
reset告诉我们可以重置读取的位置。
1 | public abstract class InputStream implements Closeable { |
所以从上面可以得知ServletInputStream是没有重写r关键的reset方法,所以行为是与InputStream保持一致的即输入流读取一遍之后就没了后续就一直返回-1。
所以解决办法就是找到重写reset的方法的类,即就找到我们常用的ByteArrayInputStream也是继承自InputStream,但是其重写了reset等方法。
我们看下源码:
注意read里面的pos变量,它是标识现在读取的流的位置,所以如果我们想多次读取输入流,需要调用上面说的reset方法重置pos为0。
1 | public |
这些搞清楚之后就是看怎么能在到咱们的filter的时候得到的request是可以读取多次同时又不影响其它地方的读取(比如controller),刚好severlet.api提供了一个叫HttpServletRequestWrapper的东西,刚好提供一种包装(专业名词:装饰器模式)的手法让我们可以包装request请求对象使其可扩展其它能力。包装高富帅哪里都吃得开。
1 | /** |
OK,到这儿输入流总算搞定了,nice,然后开始Filter上场了。
Filter
1 |
|
1 | /** |
1 |
|
1 |
|
因为我们用了graphql,有些地方还用了dsl,所以正则是魔鬼,我写崩溃了差点,当然如果有更好的方法请告诉我,万分感谢。
长出一口气…..
本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。