Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dependency injection 如何让Jersey使用HttpServletResponse包装器调用资源方法?_Dependency Injection_Jax Rs_Jersey 2.0_Hk2 - Fatal编程技术网

Dependency injection 如何让Jersey使用HttpServletResponse包装器调用资源方法?

Dependency injection 如何让Jersey使用HttpServletResponse包装器调用资源方法?,dependency-injection,jax-rs,jersey-2.0,hk2,Dependency Injection,Jax Rs,Jersey 2.0,Hk2,我试图系统地解决HTTP响应拆分问题。我已经为HttpServletResponse开发了一个名为HardenedHttpServletResponse的包装类,该类可以减少分裂尝试 遗憾的是,我无法让Jersey使用我的HardenedHttpServletResponse调用我的资源方法。我尝试时得到nulls 这是一个带有HTTP响应拆分漏洞的人为JAX-RS资源,可通过将百分比编码的CRLF(%0d%0a)放入文件名查询参数中加以利用: AttachmentResource.java:

我试图系统地解决HTTP响应拆分问题。我已经为HttpServletResponse开发了一个名为HardenedHttpServletResponse的包装类,该类可以减少分裂尝试

遗憾的是,我无法让Jersey使用我的HardenedHttpServletResponse调用我的资源方法。我尝试时得到nulls

这是一个带有HTTP响应拆分漏洞的人为JAX-RS资源,可通过将百分比编码的CRLF(
%0d%0a
)放入文件名查询参数中加以利用:

AttachmentResource.java

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

@Path("/attachment")
@Produces(MediaType.APPLICATION_JSON)
public final class AttachmentResource {
    @GET
    @Path("/file")
    public StreamingOutput getAttachment(
        @Context HttpServletResponse response,
        @QueryParam("filename") String filename
    ) throws Exception {
        response.setHeader(
            "content-disposition",
            "attachment; filename=" + filename
        );
        return new DummyStreamingOutput();
    }
}
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

private static DummyFileStreamingOutput implements StreamingOutput {
    @Override
    public void write(OutputStream outputStream) throws IOException, WebApplicationException {
        String message = "Hello, World!";
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.ws.rs.core.Context;

final class HardenedHttpServletResponse extends HttpServletResponseWrapper {
    @Inject
    HardenedHttpServletResponse(@Context HttpServletResponse response) {
        super(response);
    }

    @Override
    public void setHeader(String name, String value) {
        mitigateResponseSplitting(name);
        mitigateResponseSplitting(value);
        super.setHeader(name, value);
    }

    @Override
    public void addHeader(String name, String value) {
        mitigateResponseSplitting(name);
        mitigateResponseSplitting(value);
        super.setHeader(name, value);
    }

    @Override
    public void setIntHeader(String name, int value) {
        mitigateResponseSplitting(name);
        super.setIntHeader(name, value);
    }

    @Override
    public void setDateHeader(String name, long date) {
        mitigateResponseSplitting(name);
        super.setDateHeader(name, date);
    }

    private void mitigateResponseSplitting(String value) {
        if (value != null && (value.contains("\r") || value.contains("\n"))) {
            throw new HttpResponseSplittingException();
        }
    }
}
下面是一个StreamingOutput的虚拟实现,使其成为一个比较完整的示例:

DummyStreamingOutput.java

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

@Path("/attachment")
@Produces(MediaType.APPLICATION_JSON)
public final class AttachmentResource {
    @GET
    @Path("/file")
    public StreamingOutput getAttachment(
        @Context HttpServletResponse response,
        @QueryParam("filename") String filename
    ) throws Exception {
        response.setHeader(
            "content-disposition",
            "attachment; filename=" + filename
        );
        return new DummyStreamingOutput();
    }
}
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

private static DummyFileStreamingOutput implements StreamingOutput {
    @Override
    public void write(OutputStream outputStream) throws IOException, WebApplicationException {
        String message = "Hello, World!";
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.ws.rs.core.Context;

final class HardenedHttpServletResponse extends HttpServletResponseWrapper {
    @Inject
    HardenedHttpServletResponse(@Context HttpServletResponse response) {
        super(response);
    }

    @Override
    public void setHeader(String name, String value) {
        mitigateResponseSplitting(name);
        mitigateResponseSplitting(value);
        super.setHeader(name, value);
    }

    @Override
    public void addHeader(String name, String value) {
        mitigateResponseSplitting(name);
        mitigateResponseSplitting(value);
        super.setHeader(name, value);
    }

    @Override
    public void setIntHeader(String name, int value) {
        mitigateResponseSplitting(name);
        super.setIntHeader(name, value);
    }

    @Override
    public void setDateHeader(String name, long date) {
        mitigateResponseSplitting(name);
        super.setDateHeader(name, date);
    }

    private void mitigateResponseSplitting(String value) {
        if (value != null && (value.contains("\r") || value.contains("\n"))) {
            throw new HttpResponseSplittingException();
        }
    }
}
以下是HttpServletResponse包装类,如果在头名称或值中检测到CR或LF字符,则通过引发异常来缓解HTTP响应拆分:

强化HttpServletResponse.java

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

@Path("/attachment")
@Produces(MediaType.APPLICATION_JSON)
public final class AttachmentResource {
    @GET
    @Path("/file")
    public StreamingOutput getAttachment(
        @Context HttpServletResponse response,
        @QueryParam("filename") String filename
    ) throws Exception {
        response.setHeader(
            "content-disposition",
            "attachment; filename=" + filename
        );
        return new DummyStreamingOutput();
    }
}
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

private static DummyFileStreamingOutput implements StreamingOutput {
    @Override
    public void write(OutputStream outputStream) throws IOException, WebApplicationException {
        String message = "Hello, World!";
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.ws.rs.core.Context;

final class HardenedHttpServletResponse extends HttpServletResponseWrapper {
    @Inject
    HardenedHttpServletResponse(@Context HttpServletResponse response) {
        super(response);
    }

    @Override
    public void setHeader(String name, String value) {
        mitigateResponseSplitting(name);
        mitigateResponseSplitting(value);
        super.setHeader(name, value);
    }

    @Override
    public void addHeader(String name, String value) {
        mitigateResponseSplitting(name);
        mitigateResponseSplitting(value);
        super.setHeader(name, value);
    }

    @Override
    public void setIntHeader(String name, int value) {
        mitigateResponseSplitting(name);
        super.setIntHeader(name, value);
    }

    @Override
    public void setDateHeader(String name, long date) {
        mitigateResponseSplitting(name);
        super.setDateHeader(name, date);
    }

    private void mitigateResponseSplitting(String value) {
        if (value != null && (value.contains("\r") || value.contains("\n"))) {
            throw new HttpResponseSplittingException();
        }
    }
}
如果response参数的类型为@Context-HttpServletResponse,Jersey将提供实际响应对象,但是如果response参数的类型为@Context-hardentedhttpservletresponse,Jersey将提供null


如何让Jersey使用HttpServletResponse包装器调用资源方法?

您只需将其添加到DI系统中即可使其可注入

resourceConfig.register(new AbstractBinder() {
    @Override
    public void configure() {
        bindAsContract(HardenedHttpServletResponse.class)
            .proxy(false)
            .proxyForSameScope(false)
            .in(RequestScoped.class);
    }
});
您需要将类
公开
及其构造函数公开,以便DI系统可以创建它。这将允许您注入
HardenedHttpServletResponse

另请参见:


回答得好。非常感谢。我不得不将其修改为.proxy(false)代码以适应。它很有效,我从中学到了很多关于HK2的具体知识,也学到了很多关于Jersey DI的知识,我可以在以后的工作中应用。对不起,我忘了这需要一个论点。它应该是
proxy(true)
。默认情况下,它是false,因此如果您不需要代理,您可以只保留前两个链式调用。您希望它代理的原因是,如果需要将其注入到单例中,那么它将被包装在线程本地代理中。但是,如果它被注入到请求范围的对象(而不是单例对象)中,那么它就不会是代理(真正的对象),因为第二个链式调用。这也是HttpServletRequest的配置方式。这就是为什么可以将其注入到singletone ContainerRequestFilter中