【Web实战】浅谈Jersey中常见的鉴权措施
字数 1487 2025-08-10 08:28:42

Jersey框架中的鉴权措施详解

0x00 前言

Jersey是一个开源的RESTful Web服务框架,实现了JAX-RS规范,提供了创建RESTful Web服务的API。与SpringMvc类似,Jersey也提供了过滤器和拦截器功能,可用于实现鉴权等业务需求。

0x01 常见鉴权措施

1.1 过滤器

Jersey过滤器是javax.ws.rs.container.ContainerRequestFilterjavax.ws.rs.container.ContainerResponseFilter接口的实现,分别用于处理HTTP请求和响应。

基本使用

ContainerRequestFilter接口包含一个方法:

public void filter(ContainerRequestContext requestContext) throws IOException;

示例鉴权过滤器:

public class AuthenticationFilter implements ContainerRequestFilter {
    @Override
    public void filter(ContainerRequestContext requestContext) {
        if (!isAuthenticated(requestContext)) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }
    }
    
    private boolean isAuthenticated(ContainerRequestContext requestContext) {
        String authHeader = requestContext.getHeaderString("Authorization");
        // 验证逻辑
        return true;
    }
}

注册过滤器:

@Component
public class AppConfig extends ResourceConfig {
    AppConfig() {
        register(AuthenticationFilter.class);
    }
}

@PreMatching注解

在Filter上使用@PreMatching可以在请求匹配之前执行过滤器,修改请求资源或影响匹配方法:

@PreMatching
public class AuthenticationFilter implements ContainerRequestFilter {
    // 实现
}

1.1.1 UriInfo处理

通过ContainerRequestContext获取UriInfo处理路径信息:

UriInfo uriInfo = requestContext.getUriInfo();

常用方法:

  • getAbsolutePath(): 获取请求的绝对路径
  • getPath(): 获取请求的路径部分
  • getRequestUri(): 返回表示完整请求URI的URI对象
  • getPathSegments(): 返回路径各段的字符串值List

注意:默认情况下Jersey不会对请求path进行解码操作,路径穿越符../也不会处理,但会处理;矩阵参数。/admin/manage/admin/manage/访问的是同一个资源。

1.1.2 ResourceInfo处理

ResourceInfo可获取处理请求的资源类和方法:

@Context
private ResourceInfo resourceInfo;

// 获取资源类
Class<?> resourceClass = resourceInfo.getResourceClass();
// 获取资源方法
Method resourceMethod = resourceInfo.getResourceMethod();

注意:使用@PreMatching时无法通过ResourceInfo获取资源信息。

1.1.3 @NameBinding使用

名称绑定机制允许创建自定义注解与过滤器关联:

  1. 定义注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@NameBinding
public @interface RequireAdminRole {}
  1. 创建过滤器:
@Provider
@RequireAdminRole
public class AdminAuthFilter implements ContainerRequestFilter {
    @Override
    public void filter(ContainerRequestContext requestContext) {
        if (!isAdmin(requestContext)) {
            requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
        }
    }
}
  1. 在资源方法上使用注解:
@Path("/admin")
@RequireAdminRole
public class AdminResource {
    // 资源方法
}

1.1.4 动态绑定

实现DynamicFeature接口动态配置过滤器匹配规则:

public class AdminDynamicFeature implements DynamicFeature {
    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        if (resourceInfo.getResourceClass().getName().contains("Admin")) {
            context.register(AdminAuthFilter.class);
        }
    }
}

1.2 自定义注解

方法拦截器实现

  1. 定义注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@NameBinding
public @interface Login {}
  1. 创建拦截器:
@Login
public class AuthenticationInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // 鉴权逻辑
        return Response.ok().entity("未登陆,无权限访问").build();
    }
}
  1. 实现InterceptionService
public class AuthInterceptor implements InterceptionService {
    private static Map<Annotation, MethodInterceptor> map = new HashMap<>();
    
    static {
        Annotation[] annotations = AuthenticationInterceptor.class.getAnnotations();
        for (Annotation annotation : annotations) {
            map.put(annotation, new AuthenticationInterceptor());
        }
    }
    
    @Override
    public List<MethodInterceptor> getMethodInterceptors(Method method) {
        List<MethodInterceptor> list = new ArrayList<>();
        for (Annotation annotation : method.getAnnotations()) {
            if (map.get(annotation) != null) {
                list.add(map.get(annotation));
            }
        }
        return list;
    }
    // 其他方法实现...
}

JAX-RS安全注解

Jersey提供标准安全注解:

  • @PermitAll
  • @DenyAll
  • @RolesAllowed

示例@RolesAllowed使用:

@RolesAllowed("ADMIN")
@Path("/secure")
public class SecureResource {
    // 资源方法
}

在过滤器中检查:

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
    Method method = resourceInfo.getResourceMethod();
    if (method.isAnnotationPresent(RolesAllowed.class)) {
        RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
        Set<String> rolesSet = new HashSet<>(Arrays.asList(rolesAnnotation.value()));
        
        if (!isUserAllowed(currentUser, rolesSet)) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
                .entity("无权限访问").build());
        }
    }
}

1.3 鉴权框架

Jersey基于Servlet规范构建,可与Shiro、SpringSecurity等主流鉴权框架集成。但需注意:

  • Jersey默认不对请求path解码
  • 不处理路径穿越符../
  • 处理;矩阵参数
  • /path/path/访问同一资源

风险提示:低版本Shiro与Jersey路径解析差异可能导致权限绕过(CVE-2023-34478)。

0x02 其他

Jersey拦截器:

  • ReaderInterceptor: 操作请求Body的Entity数据流
  • WriterInterceptor: 操作响应Body的Entity数据流

可用于数据压缩/解压缩、格式转换等。

审计要点

  1. 检查UriInfo路径匹配是否存在规范化问题导致的绕过
  2. 验证动态绑定的匹配逻辑是否合理全面
  3. 确认过滤器与拦截器的执行顺序是否可能导致权限问题
  4. 检查与第三方安全框架集成时的路径解析差异
  5. 验证@NameBinding注解是否覆盖所有需要保护的方法
Jersey框架中的鉴权措施详解 0x00 前言 Jersey是一个开源的RESTful Web服务框架,实现了JAX-RS规范,提供了创建RESTful Web服务的API。与SpringMvc类似,Jersey也提供了过滤器和拦截器功能,可用于实现鉴权等业务需求。 0x01 常见鉴权措施 1.1 过滤器 Jersey过滤器是 javax.ws.rs.container.ContainerRequestFilter 和 javax.ws.rs.container.ContainerResponseFilter 接口的实现,分别用于处理HTTP请求和响应。 基本使用 ContainerRequestFilter 接口包含一个方法: 示例鉴权过滤器: 注册过滤器: @PreMatching注解 在Filter上使用 @PreMatching 可以在请求匹配之前执行过滤器,修改请求资源或影响匹配方法: 1.1.1 UriInfo处理 通过 ContainerRequestContext 获取 UriInfo 处理路径信息: 常用方法: getAbsolutePath() : 获取请求的绝对路径 getPath() : 获取请求的路径部分 getRequestUri() : 返回表示完整请求URI的URI对象 getPathSegments() : 返回路径各段的字符串值List 注意 :默认情况下Jersey不会对请求path进行解码操作,路径穿越符 ../ 也不会处理,但会处理 ; 矩阵参数。 /admin/manage 和 /admin/manage/ 访问的是同一个资源。 1.1.2 ResourceInfo处理 ResourceInfo 可获取处理请求的资源类和方法: 注意 :使用 @PreMatching 时无法通过 ResourceInfo 获取资源信息。 1.1.3 @NameBinding使用 名称绑定机制允许创建自定义注解与过滤器关联: 定义注解: 创建过滤器: 在资源方法上使用注解: 1.1.4 动态绑定 实现 DynamicFeature 接口动态配置过滤器匹配规则: 1.2 自定义注解 方法拦截器实现 定义注解: 创建拦截器: 实现 InterceptionService : JAX-RS安全注解 Jersey提供标准安全注解: @PermitAll @DenyAll @RolesAllowed 示例 @RolesAllowed 使用: 在过滤器中检查: 1.3 鉴权框架 Jersey基于Servlet规范构建,可与Shiro、SpringSecurity等主流鉴权框架集成。但需注意: Jersey默认不对请求path解码 不处理路径穿越符 ../ 处理 ; 矩阵参数 /path 和 /path/ 访问同一资源 风险提示 :低版本Shiro与Jersey路径解析差异可能导致权限绕过(CVE-2023-34478)。 0x02 其他 Jersey拦截器: ReaderInterceptor : 操作请求Body的Entity数据流 WriterInterceptor : 操作响应Body的Entity数据流 可用于数据压缩/解压缩、格式转换等。 审计要点 检查 UriInfo 路径匹配是否存在规范化问题导致的绕过 验证动态绑定的匹配逻辑是否合理全面 确认过滤器与拦截器的执行顺序是否可能导致权限问题 检查与第三方安全框架集成时的路径解析差异 验证 @NameBinding 注解是否覆盖所有需要保护的方法