未经许可,不得转载。
文章目录

Actuator未授权访问(CVE-2019-3778)
Spring Boot Actuator 是 Spring Boot 提供的一个强大的工具,用于帮助监控和管理 Spring Boot 应用程序。它提供了一系列的端点(Endpoints),通过这些端点可以获取应用程序的各种运行时信息,比如健康状况、性能指标、Bean 列表、环境变量等,还能对应用进行一些动态操作,如刷新配置等。
在基于 Maven 构建的项目里,若要引入 Spring Boot Actuator 功能,可在 pom.xml 文件中添加 spring-boot-starter-actuator 依赖,如下方截图所示:

同时需要在 application.yml 配置文件中,通过 “include” 设置 Actuator 端点:

如上图所示,exposure(译为 “暴露”)中开放了多个 Actuator 端点,即 info(应用信息)、health(健康检查)、beans(Bean 信息)、env(环境变量)、metrics(指标)、heapdump(堆转储)。这意味着外部用户可以直接访问这些端点获取敏感信息,存在较大的安全风险。
为了解决上述未授权访问敏感信息的问题,我们可以对 application.yml 进行安全配置,示例如下:
server:
port: 8088
management:
server:
port: 8089 # 单独为管理端点设置端口,也可不单独设置
endpoints:
web:
exposure:
include: info, health # 在网站上开放这两个端点
security:
enabled: true # 启用安全控制
endpoint:
health:
show-details: when-authorized # 健康检查端点,仅授权用户可见详细信息
info:
show-details: when-authorized # 应用信息端点,仅授权用户可见详细信息
这里需要配合 Spring Security 进行用户认证和角色分配。可以在 pom.xml 中添加 Spring Security 依赖,并创建相应的配置类来实现用户认证逻辑。
综上,审计思路为:在 pom.xml 中搜索 spring-boot-starter-actuator。
Swagger未授权访问(CNVD-2021-30167)
Swagger 是一种广泛使用的 API 文档生成工具,它能够自动化地生成并展示 REST API 的文档界面。
Spring Boot 项目中,通常通过 springfox-swagger2 或 springdoc-openapi 来集成 Swagger。通过 Swagger 提供的 UI,开发人员能够方便地查看和测试 API。
在基于 Maven 构建的项目中,如果想要集成 Swagger UI,可以通过添加相应的依赖来实现。例如,使用 springfox-swagger2 的方式如下:
<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>
然而,如果没有做适当的安全配置,外部用户可以直接访问应用程序 API 接口,导致敏感信息泄露等安全隐患。
我们可以通过创建一个安全配置类,来限制对 Swagger UI 的访问。通常可以配置只允许特定角色的用户访问 Swagger UI 页面和 API 文档。
示例代码如下:
@Configuration
public class SwaggerSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/swagger-ui/**", "/v2/api-docs/**").hasRole("ADMIN") // 只允许 ADMIN 角色访问
.anyRequest().authenticated()
.and()
.httpBasic(); // 配置基本认证
}
}
综上,审计思路为:在 pom.xml 中搜索 springfox-swagger-ui。
Druid未授权访问(CNVD-2019-20041)
Druid 是阿里巴巴开源的数据库连接池,它不仅提供了高性能的数据库连接管理,还集成了监控功能,可以通过 Web 界面查看 SQL 执行情况、监控数据库连接、查看慢查询等信息。
在 Spring Boot 项目中,通常通过引入 druid-spring-boot-starter 依赖来集成 Druid 连接池:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.18</version>
</dependency>
默认情况下,Druid 会提供一个管理页面,访问地址为:
http://localhost:8080/druid
如果未做访问限制,任何人都可以直接访问该页面,查看数据库连接池信息、SQL 执行情况,甚至可能会被利用执行 SQL 注入。
解决方案:
1、在 application.yml 配置文件中,设置 Druid 监控页面的用户名和密码:
spring:
datasource:
druid:
stat-view-servlet:
enabled: true # 启用Druid监控页面
login-username: aduTsrxun # 设置登录用户名
login-password: aY5is/1R@2n13 # 设置登录密码
同时在该文件中配置 allow 和 deny 参数,限制只有特定 IP 可以访问:
spring:
datasource:
druid:
stat-view-servlet:
allow: 192.168.1.100,127.0.0.1 # 仅允许这些IP访问
deny: 0.0.0.0/0 # 拒绝所有其他IP
除了 Druid 自带的用户认证机制,还可以使用 Spring Security 限制对 /druid/** 相关路径的访问:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/druid/**").hasRole("ADMIN") // 只有ADMIN角色可以访问Druid管理页面
.anyRequest().authenticated()
.and()
.httpBasic(); // 启用基本认证
}
}
综上,审计思路为:在 pom.xml 中搜索 druid-spring-boot-starter。
鉴权流程
在 Web 应用中,权限控制(鉴权)是确保系统安全性的关键环节。Spring Boot 提供了多种鉴权方式。
1. 过滤器 (Filter) 进行鉴权
javax.servlet.Filter 接口中的 doFilter 方法用于拦截请求,执行鉴权逻辑。如果请求路径匹配 Filter 配置的拦截规则,则会执行 doFilter 方法,并根据用户权限决定是否放行。
整体流程如下:
1、在过滤器中获取 HttpServletRequest(拦截客户端请求),并解析请求的 Session 或 Token。
2、检查 Session 是否有效,或者解析 Token 以获取用户身份信息。
3、判断用户是否具有访问该资源的权限。
4、放行请求,允许访问目标资源。
5、重定向到登录页或返回 403 Forbidden 响应。
示例代码如下:
@WebFilter(urlPatterns = "/*") // 拦截所有请求
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取 Session
HttpSession session = req.getSession(false); // 不创建新 Session
if (session == null || session.getAttribute("user") == null) {
// 未登录或 Session 失效,重定向到登录页
res.sendRedirect("/login");
return;
}
// Session 存在,用户已登录,继续请求
chain.doFilter(request, response);
}
}
2. 基于拦截器 (HandlerInterceptor) 进行鉴权
除了 Filter,Spring 还提供了 HandlerInterceptor 进行请求拦截。拦截器适用于 Spring MVC 处理流程,它可以在请求到达 Controller 之前进行身份校验。
示例代码如下:
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
response.sendRedirect("/login");
return false; // 拦截请求
}
return true; // 继续执行
}
}
3. JWT认证
相比 Session,使用 JWT(JSON Web Token) 可以减少服务器存储负担。
具体流程为:
1、用户登录后,服务器生成 JWT,并返回给客户端。
2、之后的每个请求,客户端都在 Authorization 头部携带 JWT。
3、服务器解析 JWT,判断用户身份和权限。
以下图为例,左侧为客户端在 Authorization 头部携带的 JWT,JWT发送到服务器端后,服务器端对其进行解密,得到右侧结果:

鉴权的示例代码如下:
String token = request.getHeader("Authorization");
if (token == null || !JwtUtil.verifyToken(token)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
return;
}
4. 案例(1)
如下图所示,代码通过判断请求 URI 是否包含"/admin/login" 或 “/admin/account” 来决定是否直接放行,因此可以实现未授权访问或越权等操作:

5. 案例(2)
在讲解本节案例之前,我们需要先了解一个关键点:在进行权限判断时,禁止使用 request.getRequestURI() 直接获取路径,否则可能会引发权限绕过。
为什么?
getRequestURI() 方法返回的是未经服务器端处理的原始路径,原始路径中可能包含特殊字符、路径跳转或其他恶意构造的请求,从而绕过服务器端的安全控制,导致未授权访问。
从下图可以看出,第 23 行代码使用了 getRequestURI() 方法来获取请求路径,而第 24 行则通过 uri.startsWith("/admin") 来判断路径是否以 /admin 开头。同时还检查了 Session 中的 loginUser 属性是否为空,并将这两个条件通过 && 进行逻辑判断。如果两个条件都为 true,则触发权限控制逻辑,提示用户需要登录,并重定向到后台登录页面。

如果能够让其中一个条件变为 false,则可以规避权限检查,继续访问受保护的资源。
在这两个条件中,Session 的部分通常不可控,但 uri.startsWith("/admin") 的判断逻辑可利用的。由于 getRequestURI() 获取的是未经服务器处理的原始路径,我们可以利用特殊字符(如分号 ;、额外的斜杠 /)来绕过路径匹配规则,构造特殊路径:
/;/admin/test
///admin/test
这些路径在 getRequestURI() 解析时不会被识别为以 /admin 开头,从而使 uri.startsWith("/admin") 返回 false,然而,在服务器实际解析请求时,特殊路径被解析为 /admin/test ,从而造成权限绕过问题。
修复建议:
使用 getRequestURL() 方法处理原始路径,它返回的是完整且经过服务器处理后的 URL,可以有效减少因特殊字符、路径跳转等问题导致的安全风险,确保权限判断更加准确和可靠。
shiro鉴权方式
Shiro是Java的一个安全框架,提供了身份验证、授权、加密和会话管理等功能。
在鉴权方面,Shiro主要有以下两种方式:
1、通过ShiroConfig文件进行配置,可在配置文件中定义角色、权限以及它们与用户的关联关系等,从而实现鉴权逻辑。这种方式适用于配置相对稳定的场景,通过配置文件集中管理权限信息,便于维护和查看整体的权限架构。
2、借助注解实现鉴权。注解方式更加灵活,可直接在代码中针对方法进行权限控制,增强了代码的可读性和维护性 。
例如,@RequiresRoles注解用于角色验证,当指定logical = Logical.AND时,如@RequiresRoles(value = {"admin", "editor"}, logical = Logical.AND),表示用户必须同时具备admin和editor两个角色才能访问相关资源;
@RequiresPermissions注解用于权限验证,当指定logical = Logical.OR时,如@RequiresPermissions(value = {"user.add", "user.del"}, logical = Logical.OR),表示用户拥有user.add或user.del其中一个权限即可访问对应资源。
Spring Security鉴权方式
Spring Security 可以通过 http.authorizeRequests() 方法来对 Web 请求进行授权保护。http.authorizeRequests() 是一个配置方法,用来启用基于 URL 的访问控制策略。它的作用是告诉 Spring Security,你需要对 HTTP 请求进行授权保护,并为不同的 URL 设置不同的访问权限。这个方法通常用于链式配置,后续可以通过不同的匹配器来设置具体的授权规则。
antMatchers() 方法用于匹配 URL 路径并进行授权控制。
示例配置:
http
.authorizeRequests()
.antMatchers("/qiushuo/**").hasRole("admin") // 访问 /qiushuo/ 路径必须具备 admin 角色
.antMatchers("/security/**").hasRole("user") // 访问 /security/ 路径必须具备 user 角色
.antMatchers("/permitAll").permitAll() // 访问 /permitAll 路径不需要认证
.anyRequest().authenticated() // 除前面定义的 URL 外,其他路径需要认证才能访问
.and()
.formLogin(); // 启用表单登录功能,用户可以通过登录界面进行身份验证。
在使用 antMatchers() 时,配置顺序会直接影响到授权的效果。较为具体的路径配置应放在前面,较为笼统的配置应放在后面。Spring Security 会按照配置的顺序进行匹配,并执行第一个匹配成功的规则。
471

被折叠的 条评论
为什么被折叠?



