关于Swagger
  Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。相关的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
主要作用
- 接口的文档在线自动生成
- 功能测试
相关项目
- Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。
- Swagger-core: 用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架进行集成。
- Swagger-js: 用于JavaScript的Swagger实现。
- Swagger-node-express: Swagger模块,用于node.js的Express web应用框架。
- Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。
- Swagger-codegen:一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码。
swagger-ui会根据我们在代码中的设置来自动生成Api说明文档,若存在相关的配置缺陷的话,可能会存在信息泄漏问题。
通过Swagger生成API文档
以Springboot整合Swagger2为例:
在pom.xml中引入Swagger2的dependency依赖,同时引入Swagger UI生成可视化的UI页面展示描述文件,以便可以与自定义的API规范进行交互并测试端点。:
xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
然后就是编写Swagger2的配置文件了:
使用相关注解进行配置:
- @Configuration注解代表上图SwaggerConfig类为配置类,自动加载到容器中。
- @EnableSwagger2则是用来启动Swagger支持,表示这是一个Spring Swagger的配置文件。
定义了Bean方法createRestApi,返回类型为Docket。传入参数DocumentationType.SWAGGER_2指定使用swagger2.0。然后通过apiInfo指定接口文档的基本信息。RequestHandlerSelectors.basePackage(“org.demo.swagger2.controller”),这是扫描注解的配置(API接口位置)。配置的是你swagger想要要加载的接口所在的包名。例如配置为com的话会扫描com包下的。这里的话扫描的是org.demo.swagger2.controller下的Controller。
```java
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).pathMapping("/").select()
// 方法需要有ApiOperation注解才能生存接口文档
.apis(RequestHandlerSelectors.basePackage("org.demo.swagger2.controller"))
// 路径使用any风格
.paths(PathSelectors.any()).build()
// 接口文档的基本信息
.apiInfo(apiInfo());
}
/*
* 接口文档详细信息
*
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Springboot整合Swagger2").description("xxx-api文档")
.termsOfServiceUrl("https://sec-in.com/").version("1.0.0").build();
}
}
```
然后在对应的Controller内加入Swagger的注解,便于生成对应的api接口文档,常用的注解有:
- @Api:一般用于Controller中,用于接口分组,描述具体的实现内容。
- @ApiImplicitParam:接口说明,用于controller控制层方法参数上,表示单独的请求参数 。
- @ApiImplicitParams:用于controller控制层方法参数上,包含多个 @ApiImplicitParam。
- @ApiOperation:对接口发起的http请求进行描述。
- @ApiResponse:描述接口的response。
- @ApiParam:表示对参数的添加元数据(说明或是否必填等)。
- @ApiModel:用于实体bean,对其进行说明
- @ApiModelProperty:用于实体bean,对实体参数进行说明。
例如下面的例子:
```java
@RestController
@Api(tags = "用户管理接口")
@RequestMapping("/user")
public class UserController {
@ApiOperation(value="获取用户信息",notes="根据id查询用户")
@ApiImplicitParam(name = "id",value = "用户id", defaultValue = "0")
@GetMapping("/")
public User getUserById(Long id) {
User user = UserService.findUser(id);
return user;
}
@ApiOperation(value="更新用户名",notes="根据id更新用户名")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用户id", defaultValue = "0"),
@ApiImplicitParam(name = "username", value = "用户名", defaultValue = "tkswifty")
})
@PutMapping("/")
public boolean updateUsernameById(String username, Long id) {
boolean = UserService.update(id,username)
return user;
}
......
}
```
实体Bean的注解:
```java
@ApiModel
public class User {
@ApiModelProperty("用户id")
private Long id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("用户地址")
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
```
启动项目后,访问/swagger-ui.html即可查看生成的接口文档:
展开查看对应的api详情:
execute后相关的response信息:
返回了预期的结果,通过上述方式即可简单的结合Swagger-UI生成对应的API接口文档。
除此以外,也可以引入如下依赖:
xml
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
然后通过在主类中配置@EnableSwagger2Doc注解,结合配置文件的方式生产对应的API接口文档。
```java
@SpringBootApplication
@EnableSwagger2Doc
public class SpringDataJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataJpaApplication.class, args);
}
}
```
配置文件applicaion.properties的部分配置:
swagger.title=Springboot整合Swagger2
swagger.description=xxx-api文档
swagger.licenseUrl=https://sec-in.com/
swagger.base-package=org.demo.swagger2.controller
此外,Swagger2已经在17年停止维护了,取而代之的是Swagger3( OpenAPI Spec)。具体可以参考https://blog.readme.com/an-example-filled-guide-to-swagger-3-2/。
在pom.xml中引入相关dependency依赖,将springdoc-openapi和Swagger UI集成在一起,以便可以与我们的API规范进行交互并测试业务接口。
xml
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-core</artifactId>
<version>1.1.49</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.1.49</version>
</dependency>
相关的注解也做了迁移:
| Swagger2 | OpenAPI Spec |
| -------------------------------------- | ------------------------------------------------------------ |
| @ApiParam | @Parameter |
| @ApiOperation(value="", notes="") | @Operation(summary = "", description = "") |
| @Api | @Tag |
| @ApiImplicitParams | @Parameters |
| @ApiImplicitParam | @Parameter |
| @ApiIgnore | @Parameter(hidden=true) Or @Operation(hidden=true) or @Hidden |
| @ApiModel | @Schema |
| @ApiModelProperty | @Schema |
| @ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) |
| @ApiResponse(code = 404, message = "") | @ApiResponse(responseCode = "404", description = "") |
同样的完成相关设置启动项目后,访问/swagger-ui.html即可查看生成的接口文档:
利用思路
可以发现一个问题,以上整合Swagger生成的API文档,是直接暴露在相关web路径下的。所有人均可以访问查看。通过这一点即可获取项目上所有的接口信息。那么结合实际业务,例如如果有文件读取相关的接口,可能存在任意文件下载,相关的业务访问可能存在未授权访问等。
常见的可利用漏洞有:
- SQL注入
- 任意文件上传/下载
- 权限控制缺失
- fastjson/jackson反序列化
- ......
以fastjson为例,例如如下接口文档,很明显是使用json进行提交的:
那么可以尝试修改提交的内容,点击execute进行提交,进行fastjson的相关测试:
也可以设置burp代理,结合repeater模块进行测试。
修复建议
-
在生产节点禁用Swagger2:
-
使用注解
@Profile({"dev","test"})
表示在开发或测试环境开启,而在生产关闭。 -
使用注解
@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
然后在测试配置或者开发配置中 添加 swagger.enable = true 即可开启,生产环境不填则默认关闭Swagger。 -
在配置文件里添加一个
swagger.enable
属性,根据不同的application-xx.yml
进行动态插入true
或false
即可。然后在Swagger配置中进行设置:
```java
@Value("${swagger.enable}")
private Boolean enable;@Bean
public Docket swaggerPersonApi10() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.demo.swagger2.controller"))
.paths(PathSelectors.any())
.enable(enable)
.build()
.apiInfo(apiInfo());
}
```
具体效果如下:
* 结合SpringSecurity/shiro进行认证授权,将Swagger-UI的URLs加入到各自的认证和授权过滤链中,当用户访问Swagger对应的资源时,只有通过认证授权的用户才能进行访问。
* 结合nginx/Filter对对应的接口端点进行访问控制。
参考资料
https://github.com/swagger-api/swagger-ui
https://springdoc.org/faq.html#how-can-i-hide-an-operation-or-a-controller-from-documentation-.
无聊的时候挖挖补天公益还是比较美好的!!! 废话不多说开整,因为上次的事情打码不严谨,差点GG了。 现在我就全部打上,哈哈哈哈嗝 万事不慌,burp前去探路 ::: hljs-center 0X01批量注册 ::: 因为没有做手机验证码功能注册,而且验证码无效…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论