我想系統地解決HTTP響應分裂問題。我開發了一個包裝類HttpServletResponse調用HardenedHttpServletResponse緩解分裂嘗試。如何讓Jersey使用HttpServletResponse包裝調用資源方法?
遺憾的是,我無法通過我的HardenedHttpServletResponse讓澤西島撥打我的資源方法。當我嘗試時,我得到null。
下面是一個HTTP響應拆分漏洞其是通過將百分比編碼CRLFs(%0d%0a
)在文件名查詢參數利用的一個人爲的JAX-RS資源:
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的包裝類,通過拋出異常減輕HTTP響應拆分,如果它檢測CR或LF字符在標題名稱或值:
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();
}
}
}
澤西供給的實際響應對象如果響應參數的類型爲@Context HttpServletResponse的,但空如果響應參數的類型爲@Context HardenedHttpServletResponse。
如何讓澤西電話與HttpServletResponse包裝調用資源方法?
很好的回答。謝謝。我不得不將它修改爲**。proxy(false)**代碼有點適應。它的工作原理和我從特定的和新澤西州的DI中學到了更多關於HK2的知識,我可以在將來的工作中應用它。 –
對不起,我忘了它需要一個參數。它應該是'proxy(true)'。默認情況下它是錯誤的,所以如果你不想要代理服務器,你可以把前兩個鏈接的呼叫留在外面。您希望代理的原因是您需要將其注入單例中,然後將其包裝在線程本地代理中。但是如果它被注入到一個請求作用域對象(而不是單例)中,那麼由於第二次鏈接調用,它不會是代理(真實對象)。這也是他如何配置HttpServletRequest。這就是爲什麼你可以將它注入一個單獨的ContainerRequestFilter –