swagger未授权访问漏洞解决办法
去年秋天,授权我帮一个做电商的访问朋友看服务器日志。凌晨三点,漏洞有个IP在十分钟内请求了/api-docs、解决/swagger-ui.html、办法/v2/api-docs三个路径,授权全部返回200。访问朋友当时没在意,漏洞觉得"接口文档嘛,解决公开就公开了"。办法两周后,授权他的访问用户订单表被人批量导出,挂在某论坛上叫卖。漏洞攻击者没用什么高级漏洞,解决就是办法顺着Swagger页面里列出的接口,挨个试了一遍——有些接口连token校验都没加。
这事不复杂,但暴露的问题很典型:Swagger默认配置下,谁都能看到你系统里有哪些接口、要传什么参数、返回什么结构。这相当于把家门钥匙插在锁上,还贴了张纸条写"欢迎光临"。
先搞清楚它为什么会被访问到
Swagger(现在叫OpenAPI)本身是个规范,springfox或springdoc这些库把它集成进Java项目后,会自动生成接口文档页面。问题出在默认行为上:springdoc-openapi从1.5版本开始,生产环境下/v3/api-docs和/swagger-ui/index.html默认就是开启的。springfox更早,很多老项目升级Spring Boot时顺手带进来的,根本没人注意。
我见过一个极端案例。某政务系统用的是JeecgBoot框架,Swagger页面直接暴露在公网上,里面有个/sys/user/exportXls接口,不需要任何权限就能导出全量用户数据。后来是被安全扫描平台通报的,修复方式简单到可笑——在application.yml里加了一行springfox.documentation.enabled=false。
几种实际可行的处理方式
最直接的办法是关掉。生产环境的配置文件里把Swagger禁用,开发环境保留。Spring Boot项目在application-prod.yml里写:
springdoc: api-docs: enabled: false swagger-ui: enabled: false 如果是springfox,对应配置是springfox.documentation.enabled=false。这招最干净,但有个前提——你得确保生产环境不会有人临时需要查接口。有些团队的做法是保留但加认证,这就涉及到第二种方案。
用Spring Security给Swagger路径加一层拦截。比如在WebSecurityConfig里配置:
http.authorizeRequests() .antMatchers("/swagger-ui/**", "/v3/api-docs/**").hasRole("ADMIN") 这样只有登录且具备管理员角色的用户才能访问文档页面。比直接关掉灵活,但配置起来稍麻烦,尤其是老项目里Security配置已经一团乱麻的情况。
还有一种场景是微服务架构。网关层做统一拦截最省事。比如在Spring Cloud Gateway里加个过滤器,判断请求路径是否包含api-docs或swagger-ui,如果是且来源IP不在白名单内,直接返回403。我见过一个团队用Nginx做这事,location匹配到swagger路径就返回444,连响应体都不给。
别忽略那些"隐藏"的暴露点
很多人关了swagger-ui页面就以为万事大吉,其实/v3/api-docs这个JSON端点才是核心。Swagger UI只是渲染层,真正泄露接口结构的是那个JSON。攻击者根本不需要打开UI页面,直接请求JSON就能拿到所有接口定义。所以禁用时要两个都关,或者两个都加认证。
另外,有些项目用了knife4j增强UI,路径是/doc.html,默认也是开的。还有Actuator端点/actuator/mappings,在某些配置下会暴露所有RequestMapping映射,效果和Swagger差不多。我一般建议客户在修复Swagger问题时,顺手检查一下Actuator的暴露端点列表。
一个容易被忽视的细节
即使你禁用了Swagger,历史版本可能已经泄露了接口结构。攻击者拿到旧的API文档后,会尝试构造请求。所以修复Swagger未授权访问只是第一步,关键接口的权限校验必须逐个确认。我朋友那个案例里,导出订单的接口本身就没有做数据权限过滤,Swagger只是让攻击者知道了这个接口的存在。换句话说,Swagger是放大镜,不是漏洞本身。
最后说个观察:很多团队在测试环境开着Swagger,生产环境忘了关,或者用同一份配置文件打包所有环境。这种"配置漂移"才是问题的根源。与其每次上线前手动检查,不如在CI/CD流水线里加一步——扫描打包后的配置文件,发现enabled=true且profile为prod就自动阻断构建。这比事后补救靠谱得多。
