背景
apisix网关之前出过一个dashboard api未授权访问漏洞:因为访问下面两个接口不需要身份认证,所以可以利用这两个接口进行rce。

在刚分析这个漏洞时,我有点困惑:

filter目录下的代码看着像是"中间件"(或者叫"过滤器")的实现,而"中间件"应该是所有请求都会经过"中间件"的业务逻辑,那为什么访问上面的两个接口就没有经过filter.AuthenticationMiddleware
中间件的认证逻辑呢?为什么访问其他接口就会经过filter.AuthenticationMiddleware
中间件的认证逻辑呢?
虽然动态调试下个断点,就能看到函数调用流程,但是我还想知道"路由"和"中间件"从web框架层来看是怎么设计的。
apisix项目用到了gin框架和droplet框架,本文记录我对这两个框架"路由"和"中间件"使用和设计的研究,以解决自己的疑惑。
分析
为什么其他接口就会经过filter.AuthenticationMiddleware
中间件的逻辑?
"业务代码"可以使用"gin框架提供的Use接口"注册中间件,比如下面这样

从上图中并没有看到filter.AuthenticationMiddleware
中间件被注册,那么为什么其他接口就会经过auth中间件的逻辑?比如GET /apisix/admin/routes HTTP/1.1
答案在droplet库:apisix通过droplet接口注册了filter.AuthenticationMiddleware
中间件

这样当访问/apisix/admin/routes
路径时,请求会经过gin框架注册的"中间件"、droplet注册的"中间件"。


有一个不严谨的结论:上面的两张图中,handlers和mws数组中的所有"函数"会被依次调用。
为什么/apisix/admin/migrate/export
接口不会经过filter.AuthenticationMiddleware
中间件的逻辑?
/apisix/admin/migrate/export
路由对应的"处理函数"并不是wgin.Wraps
包装的,这样代码流程会不从gin框架转移到droplet框架

对比可以看到/apisix/admin/routes
路由对应的"处理函数"是wgin.Wraps
返回的,这样代码流程会从gin框架转移到droplet框架

小结:gin框架和droplet框架通过wgin.Wraps
包装的func(ctx *gin.Context)
函数类型连接到了一起。
怎么修复的?
从这个commit中可以看到:
总结
- 本文只零散地记录一小部分gin和droplet框架的内部逻辑,对gin路由和中间件实现有兴趣的可以看这篇文章
- 在分析过程中感觉"实现一个web框架"非常需要"接口"或者"函数类型",比如net/http和gin框架的连接、gin框架和droplet框架的连接,都是依靠"接口"或者"函数类型"来通信。
参考
漏洞分析