掘金 后端 ( ) • 2024-04-28 17:27

上周五遇到了一个 Bug,没有任何异常,困扰了我一个小时,差点连周末都过不好了。最后没办法,请教了组内的同学,没想到竟被他 1 分钟解决了!

事情的起因,只是因为我把一个接口从 @GetMapping 改成了 @PostMapping ,然后接口就报以下的错误:

image.png 没有任何的 WARN 或者 ERROR 日志!
网上搜了一下,也没有什么有效的信息,万能的 AI 给出了下面这样的回答:

image.png 404 的错误太常见了,有很多原因造成这一结果。

但可以确定的是,我的请求路径和控制器配置都是没有问题的,因为只要要把 @PostMapping 改回 @GetMapping ,一切都运行正常。

在这种情况下,搜索引擎和AI,除了给我造成干扰误导排查方向外,不能起到什么实质性的作用。

无奈,我只能硬着头皮打开 DEBUG 日志,尝试对照源码,去解决问题了。

不幸的是,DEBUG 日志实在太多了,里面也没有任何异常。我刚学 SpringBoot 不久,这些碎片化的日志,不能引起我的任何联想,因此,实质上也起不到辅助排查的作用。

折腾了一个多小时,还是没有什么头绪,明天就周末了,带着这个 Bug,周末恐怕都休息不好。于是,我就硬着头皮找了组内一个比较有经验的同学帮忙看一下。

他过来翻了翻日志,查看了一下配置类,淡淡地说到,你打开了 Csrf 验证,但是请求却没带 Token。说罢,指导我加上了一行代码:

.csrf().disable()

然后,再次访问,竟然就真的可以了!整个过程也就 1 分钟左右!

我这个小弱鸡的心灵着实有些触动。于是追问到,大神你是怎么看出来的呀。

“没什么,就是经验多了。日志里面有些信息,比如 token 相关的, 其实已经提示了你答案。不过,需要你对框架比较了解,才能 get 到这些信息。新手遇到这种没有明显异常的问题,确实会比较费劲。”

“那有没有什么办法,可以快速搞懂这种框架问题啊,每次遇到都挺烦躁的,不仅影响研发进度,也影响心情” , 上进的我还是想从大神这里获取更多的经验。

“额….我想想”,大神迟疑了一会儿,“你可以试试这个 XCodeMap 插件“,”它可以提供更丰富的信息,图形化的形式,可以较为容易看出可能存在的问题。实在看不出,你也可以基于这些信息再去问搜索引擎或者AI”。

“感谢大神,我去试一下”。

试用了一下,这个工具画出了下面的序列图:

image.png 我虽然不懂什么 Csrf 的原理,但是这个图已经可以清晰地表达出问题了,在 SpringBoot 的FilterChain 中,走到 CsrfFilter 就终止了,并且调用了一个 AccessDeniedHandler。

看起来,这个序列图是实时动态采集的,而且做了很多剪枝,把一些关键调用给标记了出来。对于 SpringBoot 系列,其会把各种 Filter 的调用情况展示出来,可以让人一眼看出来是哪个 Filter 出了问题。

点击 CsrfFilter 的 doFilter 方法,可以看到以下代码:

image.png 这个代码可以看出来,Csrf 的原理(以CookieCsrfToken为例)就是取两个token进行比对。其中一个从请求的 Header 或者 Parameter 中读出。另外一个,从 Cookie 中读出。

image.png 由于浏览器的同源策略,攻击网站无法获取本网站的Cookie,也即其无法完成下面这样的JS操作:

image.png 但是本网站可以通过上面的操作,把 Cookie 中的token设置到 Header 中,这样就达到了避免 CSRF 攻击的效果。

不过,这里还有一个小插曲,csrf 验证失败,本意应该是报 403 错误码,然后转发到 “/403” 页面,只是因为我没有配置 “/403” 页面,最终才报了404 错误。

image.png

这次由 Csrf 引起的 404 错误,就到此为止了。

我独自完成了后面的排查,还是很开心的。我没有大神那样丰富的经验,可以凭借只言片语的日志信息,就可以推断出问题所在。但我借助 XCodeMap 绘制的动态序列图,按图索骥,搞清楚了问题的来龙去脉。这让我想起了下面的一句话:

人类有了弓箭,拳头就不再是绝对硬实力了。好的工具,可以削平人与人的差距!

感觉自己与大神接近了不少!

参考资料:

  1. http://xcodemap.tech/