浅谈Spring与安全约束SecurityConstraint
字数 1841 2025-08-06 12:20:59
Spring与安全约束SecurityConstraint深度解析
0x00 安全约束概述
安全约束(Security Constraint)是Java Web应用程序中实现访问控制的重要机制,用于保护Web资源(Servlet、JSP、HTML文件等)。它定义了访问资源所需的身份验证要求和安全限制。
安全约束三要素
- 安全约束名称:可选元素,用于管理和调试
- Web资源集合:要保护的资源集合(URL模式+HTTP方法)
- 角色名:允许访问资源的角色名称
0x01 SecurityConstraint实现原理
1.1 配置方式
web.xml配置示例
<security-constraint>
<web-resource-collection>
<web-resource-name>Private</web-resource-name>
<url-pattern>/private/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
Spring Boot配置方式
通过@Configuration类配置,不同容器有不同的实现方式。
1.2 各容器实现细节
1.2.1 Tomcat实现
配置示例:
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addContextCustomizers(context -> {
SecurityConstraint constraint = new SecurityConstraint();
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/admin/*");
constraint.addCollection(collection);
constraint.addAuthRole("admin");
context.addConstraint(constraint);
});
return tomcat;
}
处理流程:
- 在
AuthenticatorBase#invoke中处理安全约束 - 通过
realm.findSecurityConstraints()查找匹配的安全约束 - 路径匹配逻辑:
- 精确匹配请求URI
- 检查
/*模式(匹配任意路径) - 检查
*.开头的后缀模式 - 检查根路径
/匹配
1.2.2 Jetty实现
依赖调整:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
配置示例:
@Bean
public JettyServletWebServerFactory servletWebServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.addServerCustomizers(server -> {
ConstraintSecurityHandler securityHandler = ...;
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec("/admin/*");
Constraint constraint = new Constraint();
constraint.setName("auth");
constraint.setRoles(new String[]{"admin"});
constraint.setAuthenticate(true);
mapping.setConstraint(constraint);
securityHandler.addConstraintMapping(mapping);
});
return factory;
}
处理流程:
- 通过
SecurityHandler#handle处理安全约束 - 使用
prepareConstraintInfo获取RoleInfo - 路径匹配逻辑:
- 精确路径匹配(
_exactMap) - 前缀匹配(
_prefixMap) - 后缀匹配(
_suffixMap)
- 精确路径匹配(
1.2.3 Undertow实现
依赖调整:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
配置示例:
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
deploymentInfo.addSecurityConstraint(
new SecurityConstraint()
.addWebResourceCollection(
new WebResourceCollection()
.addUrlPattern("/admin/*"))
.setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.DENY)
.addRoleAllowed("admin"));
});
return factory;
}
处理流程:
- 通过
ServletSecurityConstraintHandler#handleRequest处理 - 使用
securityPathMatches.getSecurityInfo()获取安全约束 - 路径匹配逻辑:
- 精确路径匹配
- 前缀匹配
- 后缀匹配
0x02 安全约束绕过风险
2.1 各容器路径处理差异
Tomcat路径处理
- 移除
;xxx/部分(分号参数) - 标准化处理(移除多余
/,处理/../)
Jetty路径处理
- 解码URI
- 规范化处理(处理
/./和/../)
Undertow路径处理
- 处理分号参数(移除
;后到下一个/前的内容) - 不处理目录穿越符(
..)
2.2 常见绕过场景
尾部斜杠绕过
场景:配置了/admin/detail的安全约束
绕过方式:访问/admin/detail/
原理:
- Spring的
AntPathMatcher和PathPattern默认支持尾部/匹配 - 安全约束配置可能未考虑尾部斜杠情况
目录穿越绕过
场景:配置了/admin/*的安全约束
绕过方式:访问/admin/../other
原理:
- Tomcat/Jetty会规范化路径,可能导致安全约束不匹配
- Spring的
PathPattern不处理..,可能导致路由匹配但安全约束不匹配
分号参数绕过
场景:配置了特定路径的安全约束
绕过方式:在路径中插入分号参数(如/admin/;param/)
原理:
- 各容器对分号参数处理方式不同
- 可能导致路径解析不一致
0x03 安全建议
- 全面测试:对所有配置的安全约束进行边界测试
- 规范化处理:在安全约束配置中考虑各种路径变体
- 使用成熟框架:考虑使用Spring Security等专业安全框架
- 容器选择:了解所选容器的安全约束实现细节
- 防御性配置:配置拒绝所有未明确允许的访问
附录:各容器关键处理类
| 容器 | 关键处理类 |
|---|---|
| Tomcat | org.apache.catalina.authenticator.AuthenticatorBase |
| Jetty | org.eclipse.jetty.security.SecurityHandler |
| Undertow | io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler |