浅谈Jersey安全
字数 1673 2025-08-06 08:34:57
Jersey框架安全分析与防护指南
1. Jersey框架概述
Jersey是一个开源的RESTful Web服务框架,实现了JAX-RS规范(JSR 311 & JSR 339)。作为JAX-RS的参考实现,Jersey提供了一套完整的、易于使用的RESTful Web服务开发框架。
1.1 基本特性
- 实现了JAX-RS 2.0规范
- 支持RESTful Web Services开发
- 提供客户端API
- 支持与Spring集成
- 可扩展的过滤器与拦截器机制
1.2 基本示例
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class HelloResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public String sayHello() {
return "{\"message\": \"Hello, Jersey!\"}";
}
}
2. Jersey请求处理流程分析
2.1 核心处理流程
- ServletContainer.service() - 入口方法,接收HTTP请求
- UriBuilder.fromUri() - 解析请求URI
- WebComponent.service() - 请求分发
- ApplicationHandler.handle() - 应用处理入口
- Runtime.process() - 核心处理逻辑
- RoutingStage.apply() - 路由匹配
- PathMatchingRouter.apply() - 路径匹配
2.2 关键安全特性
- 默认不对路径穿越符(
../)进行处理 - 默认不对URI进行解码(
@Encoded注解可控制) - 会处理矩阵参数(分号后的内容)
- 支持尾部斜杠匹配
3. 安全风险与防护措施
3.1 信息泄露风险
3.1.1 WADL信息泄露
风险描述:
默认情况下,Jersey会在/application.wadl路径暴露应用程序结构信息,包括URL、HTTP方法、参数等。
防护措施:
- 通过web.xml禁用:
<init-param>
<param-name>jersey.config.server.wadl.disableWadl</param-name>
<param-value>true</param-value>
</init-param>
- 通过ResourceConfig禁用:
@Component
public class AppConfig extends ResourceConfig {
AppConfig() {
property(ServerProperties.WADL_FEATURE_DISABLE, true);
}
}
3.2 权限绕过风险
3.2.1 路径解析差异
风险点:
- Jersey与安全框架(如Shiro)对路径解析存在差异
- Jersey默认不处理
../,而安全框架可能处理
示例绕过:
/api/../bypass
防护措施:
- 在安全过滤器中统一使用Jersey的路径获取方式
- 对路径进行规范化处理
3.2.2 尾部斜杠绕过
风险点:
- Jersey默认支持尾部斜杠匹配(
/path和/path/等效)
防护措施:
- 在权限检查中统一处理尾部斜杠情况
- 使用精确匹配而非前缀匹配
3.2.3 路径获取方法差异
路径获取方法对比:
| 方法 | 描述 | 是否解码 | 处理../ |
处理矩阵参数 |
|---|---|---|---|---|
| getPath() | 获取路径部分 | 是 | 否 | 是 |
| getRawPath() | 获取原始路径 | 否 | 否 | 是 |
| getPathSegments() | 获取路径段 | 是 | 否 | 是 |
防护建议:
- 使用
getPathSegments()获取标准化路径 - 避免直接使用
getPath()进行权限检查
3.3 任意文件下载风险
风险代码示例:
@GET
@Path("/{path:.*}")
public Response fileDownload(@PathParam("path") @Encoded String path) {
File file = new File("/base" + path);
// 文件读取逻辑
}
利用条件:
- 路径参数未校验
- 中间件对
../处理宽松(如Undertow)
防护措施:
- 校验路径参数:
if (path.contains("..")) {
throw new SecurityException("Path traversal attempt");
}
- 使用规范化路径:
Path normalized = Paths.get("/base", path).normalize();
if (!normalized.startsWith("/base")) {
throw new SecurityException("Invalid path");
}
- 限制文件目录:
@Value("${safe.directory:/safe}")
private String safeDirectory;
File file = new File(safeDirectory, sanitize(path));
4. 安全开发建议
4.1 输入验证
- 对所有路径参数进行严格校验
- 使用白名单而非黑名单
- 对正则路由限制匹配范围
4.2 权限控制
- 使用标准安全框架(如Spring Security)
- 确保安全框架与Jersey解析一致
- 避免基于字符串匹配的权限检查
4.3 配置加固
- 禁用开发模式特性
- 关闭WADL等调试接口
- 配置合理的CORS策略
4.4 安全过滤器示例
@Provider
@Priority(Priorities.AUTHORIZATION)
public class SecurityFilter implements ContainerRequestFilter {
private static final Set<String> ALLOWED_PATHS = Set.of(
"/api/public/",
"/login"
);
@Override
public void filter(ContainerRequestContext ctx) {
String path = ctx.getUriInfo().getPath();
// 标准化处理
path = path.replaceAll("/+", "/");
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
// 白名单检查
if (!ALLOWED_PATHS.contains(path)) {
// 认证检查
String auth = ctx.getHeaderString("Authorization");
if (!isValidToken(auth)) {
ctx.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
}
}
5. 总结
Jersey作为成熟的REST框架,在提供便利开发的同时也存在特定的安全考量点。开发者应特别注意:
- 路径解析与安全框架的协同
- 敏感接口的信息泄露防护
- 文件操作的安全边界控制
- 输入参数的严格验证
通过遵循安全开发实践和适当的配置加固,可以构建安全可靠的Jersey应用。