Swagger

关于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规范进行交互并测试端点。:

<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。

@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,对实体参数进行说明。

  例如下面的例子:

@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的注解:

@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详情:

返回了预期的结果,通过上述方式即可简单的结合Swagger-UI生成对应的API接口文档。

  除此以外,也可以引入如下依赖:

<dependency>
    <groupId>com.spring4all</groupId>
    <artifactId>swagger-spring-boot-starter</artifactId>
    <version>1.8.0.RELEASE</version>
</dependency>


 

  然后通过在主类中配置@EnableSwagger2Doc注解,结合配置文件的方式生产对应的API接口文档。

@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)。具体可以参考A Visual Guide to What's New in Swagger 3.0

  在pom.xml中引入相关dependency依赖,将springdoc-openapi和Swagger UI集成在一起,以便可以与我们的API规范进行交互并测试业务接口。

<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>

相关的注解也做了迁移:

Swagger2OpenAPI 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进行提交的:
 

图片.png


  那么可以尝试修改提交的内容,点击execute进行提交,进行fastjson的相关测试:
 

图片.png


  也可以设置burp代理,结合repeater模块进行测试。

修复建议

  • 在生产节点禁用Swagger2:

    • 使用注解@Profile({"dev","test"}) 表示在开发或测试环境开启,而在生产关闭。

    • 使用注解@ConditionalOnProperty(name = "swagger.enable", havingValue = "true") 然后在测试配置或者开发配置中 添加 swagger.enable = true 即可开启,生产环境不填则默认关闭Swagger。

    • 在配置文件里添加一个swagger.enable属性,根据不同的application-xx.yml进行动态插入truefalse即可。然后在Swagger配置中进行设置

  @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

F.A.Q

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值