文章目录
- 0.前言
- 漏洞
- 受影响的Spring产品和版本
 
 
- 1.参考文档
- 2.基础介绍
- 描述
 
- 3.解决方案
- 3.1. 升级版本
 
- 4.HeaderHttpSessionIdResolver 解析
- 5. Spring Session 使用教程
 
 
 
0.前言
背景:公司项目扫描到 CVE-2023-20866:在Spring Session中会将会话ID记录到标准输出流
漏洞
中风险 | 2023年4月12日 | CVE-2023-20866
描述
在Spring Session 3.0.0版本中,会将会话ID记录到标准输出流中。此漏洞将敏感信息暴露给那些可以访问应用程序日志的人,可能被用于会话劫持。
描述
 在Spring Session 3.0.0版本中,会将会话ID记录到标准输出流中。此漏洞将敏感信息暴露给那些可以访问应用程序日志的人,可能被用于会话劫持。
具体而言,使用了HeaderHttpSessionIdResolver,应用程序存在漏洞。
 未使用HeaderHttpSessionIdResolver。则应用程序不受影响
受影响的Spring产品和版本
Spring Session 3.0.0
1.参考文档
CVE 官方网站 https://www.cve.org/CVERecord?id=CVE-2023-20866
 spring官方网站 https://spring.io/security/cve-2023-20866
 
2.基础介绍
CVE-2023-20866:在Spring Session中会将会话ID记录到标准输出流
 中风险 | 2023年4月12日 | CVE-2023-20866
描述
在Spring Session 3.0.0版本中,会将会话ID记录到标准输出流中。此漏洞将敏感信息暴露给那些可以访问应用程序日志的人,可能被用于会话劫持。
具体而言,当满足以下条件时,应用程序存在漏洞:
-  使用了HeaderHttpSessionIdResolver。 未使用HeaderHttpSessionIdResolver。则应用程序不受影响: 
受影响的Spring产品和版本
 Spring Session 3.0.0
3.解决方案
3.1. 升级版本
受影响版本的用户应升级到Spring Session 3.0.1。
4.HeaderHttpSessionIdResolver 解析
HeaderHttpSessionIdResolver 是 HttpSessionIdResolver 的一个实现,它负责从 HTTP 请求和响应的头部中解析和写入会话 ID。
以下是 HeaderHttpSessionIdResolver 的主要方法的源码解析:
- 构造函数
public HeaderHttpSessionIdResolver(String headerName) {
    Assert.hasText(headerName, "headerName must not be empty");
    this.headerName = headerName;
}
构造函数接收一个字符串参数 headerName,这个参数表示会话 ID 在 HTTP 头部的键。这个函数首先检查 headerName 是否为空,如果为空则抛出异常。然后,将 headerName 保存到类的私有字段中。
- resolveSessionIds方法
@Override
public List<String> resolveSessionIds(HttpServletRequest request) {
    String sessionId = request.getHeader(this.headerName);
    return (sessionId != null ? Collections.singletonList(sessionId) : Collections.emptyList());
}
resolveSessionIds 方法从 HTTP 请求的头部中获取会话 ID。如果找到了会话 ID,那么返回一个只包含这个会话 ID 的列表。如果没有找到会话 ID,那么返回一个空的列表。
- setSessionId方法
@Override
public void setSessionId(HttpServletRequest request, HttpServletResponse response, String sessionId) {
    response.setHeader(this.headerName, sessionId);
}
setSessionId 方法将会话 ID 写入到 HTTP 响应的头部中。这样,客户端在接收到响应后可以从头部中获取到会话 ID。
- expireSession方法
@Override
public void expireSession(HttpServletRequest request, HttpServletResponse response) {
    response.setHeader(this.headerName, "");
}
expireSession 方法将 HTTP 响应的头部中的会话 ID 设置为空字符串。这样,客户端在接收到响应后会认为会话已经过期。
HeaderHttpSessionIdResolver 类的实现非常简单,但是它却是 Spring Session 中关于会话管理的重要组成部分。
5. Spring Session 使用教程
Spring Session 提供 API 和实现,用于在任何分布式应用程序中管理用户会话信息。会话可以在多个节点之间共享,这对于构建高可用、可扩展的应用程序非常有用。
- 添加Spring Session和相应存储类型的依赖项
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
这里使用的是 Redis 作为会话信息的存储。
- 配置Spring Session:
@EnableRedisHttpSession 
public class HttpSessionConfig {
    @Bean
    public LettuceConnectionFactory connectionFactory() {
        return new LettuceConnectionFactory(); 
    }
}
此处 @EnableRedisHttpSession 注解启用了 Spring Session 支持,并创建了一个LettuceConnectionFactory Bean用来连接Redis。
- 使用Spring Session:
@Controller
public class HelloController {
    
    @RequestMapping("/setSession")
    @ResponseBody
    public String setSession(HttpServletRequest request) {
        request.getSession().setAttribute("message", "Hello Spring Session");
        return "Session Set";
    }
    @RequestMapping("/getSession")
    @ResponseBody
    public String getSession(HttpServletRequest request) {
        return (String) request.getSession().getAttribute("message");
    }
}
setSession()方法将一个属性存储到会话中,getSession()方法从会话中获取该属性。
- 确保你的应用程序能够连接到Redis服务器,这样Spring Session就可以正常工作。

















