线上服务403 Forbidden错误的调查

最近刚刚从老外哪里接手了一个服务, 然后需要每天检查一下服务的状态。 本来这个服务已经运行了好几年也没有改动,是一个相对稳定的服务。

在昨天对这个服务进行例行公事的检查的时候, 发现线上监控工具NewRelic报了大量的Forbidden Error。 当时的第一反应就是是不是被攻击了。

然后点进上图的“Forbidden”链接, 看具体的请求访问的明细, 首先可以在右上角看到在过去的24小时内, 一共收到了5858个这样的错误。

然后可以看到访问的Request URI 是 类似“/wls-wsat/CoordinatorPortType”, 或者是"/wls-wsat/CoordinatorPortType11", 使用的HttpMethod是“Post”或者是“PROPFIND”, 然后google了一下”/wls-wsat/CoordinatorPortType11“,然后就找到了下面 blog.alertlogic.com/blo

According to the POC, the wls-wsat/CoordinatorPortType endpoint is where the vulnerability exists, but the endpoints below have also been listed as possible vulnerable entry points for this attack:
wls-wsat/RegistrationPortTypeRPC
wls-wsat/ParticipantPortType
wls-wsat/RegistrationRequesterPortType
wls-wsat/CoordinatorPortType11
wls-wsat/RegistrationPortTypeRPC11
wls-wsat/ParticipantPortType11
wls-wsat/RegistrationRequesterPortType11

看起来的确是有人对我们的服务进行漏洞扫描,然后赶紧把这个问题告诉了安全部门, 让他们去调查这些请求的来源。

然后就自然想调查一下是那段代码起了作用报出了了这个403 Forbidden Error。因为是接手的代码, 对代码并不熟悉,印象中没有那段代码打印这样的Error Message, 而且从在线日志Kibana上来看, 似乎请求没有运行到我们的代码, 就被Spring Framework的代码给拦截了。

首先尝试着重现这个问题, 很幸运, 简单的通过curl命令来访问的服务就重现了这个问题。

curl -d "param1=value1" -X POST "http://localhost:8071/wls-wsat/CorordinatePortType11"

既然本地能够重现, 那么事情就比较好办了, 猜测是Spring那个拦截器的起了作用,在本地把spring framework的debug log打开

<logger name="org.springframework" level="DEBUG"/>

然后就看到以下的error

原来是CSRFFilter起了作用。原来CSRFFilter默认在Spring Boot中代开。 CSRF 是cross site request forgery的缩写。 它是主要用来防止客户无意或者是被人利用恶意的多次提交表单。 所以为了只让客户的请求只被提交一次, 服务器端每次都会在生成表单页面的时候添加一个隐藏的表单元素“_csrf”,然后让用户提交表单的时候会被一起提交到服务器端。 然后服务器端会对_csrf进行检查, 通过判断是不是一个有效的CSRF token来判断内容有没有多次提交。因为主要为了防止恶意的写操作, 所以缺省情况下CSRF只对请求的方法不是Get, Options, Head, Trace之外的请求进行拦截。

在我们的代码里面, 被CSRFFilter拦截下来之后, 发现当前的请求并没有携带CSRF token, CSFRFilter就把处理交给了accessDeniedHandler.

然后在accessDeniedHandler的实现org.springframework.security.web.access.AccessDeniedHandlerImpl中, 调用了response.senderror并设置了Response的StatusCode是403。

response.sendError所做的事情就是把当前的request访问的uri改成了“/error”, 最终Spring Framework的BasicErrorController就会接收到这个请求, 并返回最终的response。

这样整个处理的流程就搞清楚了,写好调查的报告就可以休息了:-)

当然你也可以关闭CsrfFilter, 但是强烈建议不要这么做, 因为这样让自己的程序很危险。 如果确认自己的服务并没有写操作, 可以通过下面的配置来关闭。

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {