摘要
本文系统梳理 Swagger 安全防护的核心方案,涵盖旧版 Swagger(SpringFox)的swagger.basic
配置实践、官方推荐的 Spring Security 方案,以及多环境管理、反向代理过滤等全链路技术。结合权威文档,明确不同方案的适用版本与场景,助力开发者构建安全合规的 API 文档体系。
一、Swagger 安全问题背景
Swagger(或 SpringDoc OpenAPI)生成的 API 文档是开发者的 “利器”,但也可能成为攻击者的 “攻击地图”。未防护的 Swagger UI 会暴露以下风险:
- 接口信息泄露:所有接口路径、参数类型及权限要求被公开;
- 越权调用风险:攻击者可直接构造恶意请求调用敏感接口;
- 版本漏洞隐患:旧版 Swagger(如 SpringFox <3.0.0)存在 CVE-2020-8908(远程代码执行)等高危漏洞。
二、旧版 Swagger 的配置实践:swagger.basic
的适用场景
2.1 适用版本与实现逻辑
swagger.basic
配置常见于旧版 Swagger 集成方案(如 SpringFox 2.x),适用于早期 Spring Boot 项目(<2.6 版本)。其核心逻辑是通过自定义过滤器实现 Basic 认证,配置示例如下(application.yml
):
yaml
# 旧版SpringFox配置(非官方)
swagger:
production: false # 是否为生产环境
basic:
enable: true # 启用Basic认证
username: zhangsan # 认证用户名
password: 123 # 认证密码(明文存储,风险高)
2.2 局限性与风险
尽管swagger.basic
在早期项目中被广泛使用,但其存在以下缺陷:
- 不再维护:SpringFox 自 2020 年起停止更新,不兼容 Spring Boot 2.6 + 及以上版本;
- 安全隐患:密码以明文形式存储在配置文件中,易泄露;认证逻辑仅通过简单过滤器实现,未与 Spring Security 深度集成,防护能力弱;
- 官方不推荐:Spring Boot 官方已明确建议迁移至 SpringDoc OpenAPI(Swagger 3.x 官方实现)。
三、官方推荐方案:Spring Security 实现 Basic 认证
SpringDoc OpenAPI(Swagger 3.x 官方实现)是当前 Spring Boot 项目的最佳选择。其安全防护需通过Spring Security实现,这是 Spring 官方唯一推荐的方案。
3.1 核心依赖(Spring Boot 3.x+)
xml
<!-- Spring Security(安全核心) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- SpringDoc OpenAPI(Swagger 3.x) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version> <!-- 2025年最新版,修复CVE-2023-25690 -->
</dependency>
3.2 核心配置类(Spring Security 集成)
通过 Spring Security 为 Swagger 路径(/swagger-ui/**
、/v3/api-docs/**
)添加 Basic 认证规则,仅授权用户可访问。配置示例如下:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 关闭CSRF(前后端分离场景)
.authorizeHttpRequests(auth -> auth
// Swagger路径需认证(触发Basic弹窗)
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").authenticated()
// 公共接口(如登录)无需认证
.requestMatchers("/api/auth/login").permitAll()
// 其他接口默认认证
.anyRequest().authenticated()
)
.httpBasic(); // 启用Basic认证
return http.build();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
// 配置认证用户(生产环境替换为数据库/LDAP)
return new InMemoryUserDetailsManager(
User.builder()
.username("zhangsan") // 用户名
.password(passwordEncoder.encode("123")) // 密码(BCrypt加密)
.roles("DEVELOPER") // 角色
.build()
);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // Spring推荐的BCrypt加密算法(不可逆)
}
}
3.3 认证流程验证
- 访问
http://localhost:8080/swagger-ui.html
,浏览器弹出 Basic 认证弹窗; - 输入
zhangsan/123
(用户名 / 密码),认证通过后加载 Swagger 文档; - 输入错误凭证,返回
401 Unauthorized
(未授权)。
四、多环境管理:@Profile 实现智能控制
通过 Spring 的@Profile
注解,可灵活控制 Swagger 的生命周期:开发 / 测试环境启用文档,生产环境自动禁用。
4.1 开发 / 测试环境(启用 Swagger+Basic 认证)
将 Swagger 配置类标记为@Profile({"dev", "test"})
,仅在指定环境生效:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
@Configuration
@Profile({"dev", "test"}) // 仅在开发/测试环境加载
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("开发环境API文档")
.version("1.0.0")
.description("仅供开发/测试人员访问"));
}
}
4.2 生产环境(彻底禁用 Swagger)
通过配置文件或@Profile
禁用生产环境的 Swagger:
yaml
# application-prod.yml(生产环境)
spring:
profiles: prod
springdoc:
swagger-ui:
enabled: false # 显式禁用Swagger UI(可选,@Profile已生效时可省略)
api-docs:
enabled: false # 禁用OpenAPI文档接口
五、全链路防护:其他关键方案
5.1 敏感接口隐藏(减少信息泄露)
通过 Swagger 注解隐藏不希望暴露的接口:
java
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
@RestController
@RequestMapping("/api/admin")
public class AdminController {
// 完全隐藏接口(不展示在文档)
@Hidden
@PostMapping("/deleteUser")
public void deleteUser() { /* 敏感操作(如删除用户) */ }
// 细粒度隐藏(保留方法名但不显示)
@Operation(hidden = true)
@GetMapping("/debug")
public void debug() { /* 内部调试接口 */ }
}
5.2 Actuator 端点控制(替代旧版配置)
Spring Boot 3.x 已弃用management.security.enabled
,改为通过以下方式控制:
- 最小化暴露端点(
application-prod.yml
):yaml
management: endpoints: web: exposure: include: "health, info" # 仅暴露健康检查和基本信息 endpoint: health: show-details: never # 不显示详细健康信息(如数据库连接状态)
- 权限限制(Spring Security):
java
.authorizeHttpRequests(auth -> auth .requestMatchers("/actuator/**").hasRole("ADMIN") # 仅ADMIN角色可访问 )
5.3 Nginx 反向代理(外部流量过滤)
通过 Nginx 限制 Swagger 和 Actuator 的外部访问:
nginx
server {
listen 80;
server_name your-domain.com;
# 限制Swagger仅内网访问(如公司办公网192.168.1.0/24)
location /swagger-ui/ {
allow 192.168.1.0/24;
deny all;
proxy_pass http://localhost:8080;
}
# 屏蔽Actuator危险端点(如/shutdown)
location = /actuator/shutdown {
return 403; # 直接返回403禁止访问
}
}
六、方案对比与最佳实践
方案 | 适用版本 | 安全性 | 维护成本 | 官方推荐 |
---|---|---|---|---|
swagger.basic (旧版) |
SpringFox 2.x(<2020) | 低(明文密码) | 高(需自定义) | ❌ |
Spring Security(官方) | Spring Boot 3.x+ | 高(BCrypt 加密) | 低(标准配置) | ✅ |
最佳实践建议:
- 新项目直接采用 Spring Security+SpringDoc 方案,避免旧版
swagger.basic
的安全隐患; - 旧项目迁移时,优先升级至 SpringDoc,并用 Spring Security 替代
swagger.basic
; - 生产环境通过
@Profile
+ 配置文件双重禁用 Swagger,开发环境通过 Basic 认证限制访问。
参考资料