Dependency injection 如何让Jersey使用HttpServletResponse包装器调用资源方法?
我试图系统地解决HTTP响应拆分问题。我已经为HttpServletResponse开发了一个名为HardenedHttpServletResponse的包装类,该类可以减少分裂尝试 遗憾的是,我无法让Jersey使用我的HardenedHttpServletResponse调用我的资源方法。我尝试时得到nulls 这是一个带有HTTP响应拆分漏洞的人为JAX-RS资源,可通过将百分比编码的CRLF(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:
%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(true)
。默认情况下,它是false,因此如果您不需要代理,您可以只保留前两个链式调用。您希望它代理的原因是,如果需要将其注入到单例中,那么它将被包装在线程本地代理中。但是,如果它被注入到请求范围的对象(而不是单例对象)中,那么它就不会是代理(真正的对象),因为第二个链式调用。这也是HttpServletRequest的配置方式。这就是为什么可以将其注入到singletone ContainerRequestFilter中