如何在 Jersey 2 中修改 QueryParam 和 PathParam

How to Modify QueryParam and PathParam in Jersey 2

我正在尝试 filter/modify Post 和 Put 调用以确保用户提供的所有参数都从 HTML 和 JS 代码中过滤,以防止 XSS 攻击。我想确保这是在 API 级别实现的,因此无论使用什么客户端,它都会受到保护。

使用 Jersey 1.x,这可以通过实施 ContainerRequestFilter 并在它们与请求的 servlet 匹配之前修改 request.getQueryParameters() 来实现。示例:http://codehustler.org/blog/jersey-cross-site-scripting-xss-filter-for-java-web-apps/

然而,对于 Jersey 2,这不可能通过实现相同的接口来实现,因为我们不能再使用 getQueryParameters() 或 getPathParameters(),而是只能使用 getUriInfo(),但是由于查询参数是不可变的。我查看了 Jersey 的 Filters and Interceptors,但不幸的是,它们仅限于提供对 headers 和 cookie 的访问权限。

我花了很多时间研究,但找不到我要找的东西。

是否有其他方法来过滤路径和查询参数?有什么我遗漏的吗?

谢谢!

您可以使用 ContainerRequestFilter,构造一个新的 URI(基于现有 URI),并通过 setRequestUri 方法在 ContainerRequestContext 中设置 URI。

@PreMatching
public class MyFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        UriBuilder builder = requestContext.getUriInfo().getRequestUriBuilder();

        // Replace a query param
        builder.replaceQueryParam("foo", "bar");

        // Remove a query param
        builder.replaceQueryParam("baz");

        // Replace path
        builder.replacePath("newPath");

        requestContext.setRequestUri(builder.build());
    }
}

然而,使用这种方法,我还没有找到一种方法来根据匹配的 Jersey 资源的 URI 模板中的参数名称替换单个路径参数,因为 "setRequestUri" 只允许在资源匹配前阶段使用。所以整个路径都需要替换。

我在下面添加了一个适用于 Jersey 2.x 的过滤器。但是,它不会对 Cookie 执行 XSS 修复,因为我还没有找到修改它们的方法。

重要的是要注意,这需要与 POJO 属性上的 @SafeHtml 结合使用才能清理这些值。

@PreMatching
public class XSSFilter implements ContainerRequestFilter
{
    /**
     * @see ContainerRequestFilter#filter(ContainerRequest)
     */
    @Override
    public void filter( ContainerRequestContext request )
    {
        cleanQueryParams( request );
        cleanHeaders( request.getHeaders() );
    }


    /**
     * Replace the existing query parameters with ones stripped of XSS vulnerabilities
     * @param request
     */
    private void cleanQueryParams( ContainerRequestContext request )
    {
        UriBuilder builder = request.getUriInfo().getRequestUriBuilder();
        MultivaluedMap<String, String> queries = request.getUriInfo().getQueryParameters();

        for( Map.Entry<String, List<String>> query : queries.entrySet() )
        {
            String key = query.getKey();
            List<String> values = query.getValue();

            builder.replaceQueryParam( key );
            for( String value : values ) {
                builder.replaceQueryParam( key, Utils.stripXSS( value ) );
            }

        }

        request.setRequestUri( builder.build() );
    }


    /**
     * Replace the existing headers with ones stripped of XSS vulnerabilities
     * @param headers
     */
    private void cleanHeaders( MultivaluedMap<String, String> headers )
    {
        for( Map.Entry<String, List<String>> header : headers.entrySet() )
        {
            String key = header.getKey();
            List<String> values = header.getValue();

            List<String> cleanValues = new ArrayList<String>();
            for( String value : values ) {
                cleanValues.add( Utils.stripXSS( value ) );
            }

            headers.put( key, cleanValues );
        }
    }
}

stripXSS 函数如下:

/**
 * Strips any potential XSS threats out of the value
 *
 * @param value
 * @return
 */
public static String stripXSS( String value )
{
    return stripXSS( value, Whitelist.none() );
}


/**
 * Strips any potential XSS threats out of the value excluding
 * the white listed HTML
 *
 * @param value
 * @param whitelist
 * @return
 */
public static String stripXSS( String value, Whitelist whitelist )
{
    if( StringUtils.isBlank( value ) )
        return value;

    // Use the ESAPI library to avoid encoded attacks.
    value = ESAPI.encoder().canonicalize( value );

    // Avoid null characters
    value = value.replaceAll("[=11=]", "");

    // Clean out HTML
    Document.OutputSettings outputSettings = new Document.OutputSettings();
    outputSettings.escapeMode( EscapeMode.xhtml );
    outputSettings.prettyPrint( false );
    value = Jsoup.clean( value, "", whitelist, outputSettings );

    return value;
}

也更新了原文post:http://codehustler.org/blog/jersey-cross-site-scripting-xss-filter-for-java-web-apps/