如何让 Jersey 使用 HttpServletResponse 包装器调用资源方法?
How do I get Jersey to call a resource method with an HttpServletResponse wrapper?
我正在尝试系统地解决 HTTP 响应拆分问题。我为 HttpServletResponse 开发了一个名为 HardenedHttpServletResponse 的包装器 class 来减轻拆分尝试。
遗憾的是,我无法让 Jersey 使用我的 HardenedHttpServletResponse 调用我的资源方法。我尝试时得到 nulls。
这是一个带有 HTTP 响应拆分漏洞的人为 JAX-RS 资源,可以通过将 percent-encoded 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();
}
}
这里是 StreamingOutput 的虚拟实现,使其成为一个完整的示例:
DummyStreamingOutput.java:
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();
}
}
这里是 HttpServletResponse 包装器 class 如果检测到 header 名称或值中的 CR 或 LF 字符,它会通过抛出异常来减轻 HTTP 响应拆分:
HardenedHttpServletResponse.java:
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 提供实际响应 object,但是 null 如果 response 参数的类型为 @Context HardenedHttpServletResponse.
如何让 Jersey 使用 HttpServletResponse 包装器调用资源方法?
您可以通过将其添加到 DI 系统使其可注入。
resourceConfig.register(new AbstractBinder() {
@Override
public void configure() {
bindAsContract(HardenedHttpServletResponse.class)
.proxy(false)
.proxyForSameScope(false)
.in(RequestScoped.class);
}
});
您将需要创建 class public
及其构造函数 public,以便 DI 系统可以创建它。这将允许您注入 HardenedHttpServletResponse
另请参阅:
- Dependency injection with Jersey 2.0
我正在尝试系统地解决 HTTP 响应拆分问题。我为 HttpServletResponse 开发了一个名为 HardenedHttpServletResponse 的包装器 class 来减轻拆分尝试。
遗憾的是,我无法让 Jersey 使用我的 HardenedHttpServletResponse 调用我的资源方法。我尝试时得到 nulls。
这是一个带有 HTTP 响应拆分漏洞的人为 JAX-RS 资源,可以通过将 percent-encoded 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();
}
}
这里是 StreamingOutput 的虚拟实现,使其成为一个完整的示例:
DummyStreamingOutput.java:
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();
}
}
这里是 HttpServletResponse 包装器 class 如果检测到 header 名称或值中的 CR 或 LF 字符,它会通过抛出异常来减轻 HTTP 响应拆分:
HardenedHttpServletResponse.java:
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 提供实际响应 object,但是 null 如果 response 参数的类型为 @Context HardenedHttpServletResponse.
如何让 Jersey 使用 HttpServletResponse 包装器调用资源方法?
您可以通过将其添加到 DI 系统使其可注入。
resourceConfig.register(new AbstractBinder() {
@Override
public void configure() {
bindAsContract(HardenedHttpServletResponse.class)
.proxy(false)
.proxyForSameScope(false)
.in(RequestScoped.class);
}
});
您将需要创建 class public
及其构造函数 public,以便 DI 系统可以创建它。这将允许您注入 HardenedHttpServletResponse
另请参阅:
- Dependency injection with Jersey 2.0