mirror of
https://github.com/apache/struts.git
synced 2026-08-05 06:36:58 +00:00
WW-5636 Harden redirect URL escaping in non-302 response body (#1737)
* Implement test for status code 200 with HTML escaping * Escape HTML in ServletRedirectResult response Escape HTML in the final location before writing to the response.
This commit is contained in:
@@ -26,6 +26,7 @@ import org.apache.struts2.util.reflection.ReflectionException;
|
||||
import org.apache.struts2.util.reflection.ReflectionExceptionHandler;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
@@ -248,7 +249,7 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec
|
||||
response.setStatus(statusCode);
|
||||
response.setHeader("Location", finalLocation);
|
||||
try {
|
||||
response.getWriter().write(finalLocation);
|
||||
response.getWriter().write(StringEscapeUtils.escapeHtml4(finalLocation));
|
||||
} finally {
|
||||
response.getWriter().close();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_SEE_OTHER;
|
||||
import static org.easymock.EasyMock.createControl;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
@@ -143,6 +144,33 @@ public class ServletRedirectResultTest extends StrutsInternalTestCase implements
|
||||
assertEquals("/context/bar/foo.jsp", writer.toString());
|
||||
}
|
||||
|
||||
public void testStatusCode200LocationIsHtmlEscapedInBody() {
|
||||
String maliciousLocation = "/bar/foo.jsp?next=<script>alert(1)</script>&x=1";
|
||||
String expandedLocation = "/context" + maliciousLocation;
|
||||
String expectedBody = "/context/bar/foo.jsp?next=<script>alert(1)</script>&x=1";
|
||||
|
||||
view.setLocation(maliciousLocation);
|
||||
view.setStatusCode(SC_OK);
|
||||
responseMock.expectAndReturn("encodeRedirectURL", expandedLocation, expandedLocation);
|
||||
responseMock.expect("setStatus", C.args(C.eq(SC_OK)));
|
||||
responseMock.expect("setHeader", C.args(C.eq("Location"), C.eq(expandedLocation)));
|
||||
StringWriter writer = new StringWriter();
|
||||
responseMock.matchAndReturn("getWriter", new PrintWriter(writer));
|
||||
|
||||
try {
|
||||
view.execute(ai);
|
||||
requestMock.verify();
|
||||
responseMock.verify();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
assertEquals(expectedBody, writer.toString());
|
||||
assertFalse("response body must not contain a raw <script> tag",
|
||||
writer.toString().contains("<script>"));
|
||||
}
|
||||
|
||||
public void testAbsoluteRedirectAnchor() {
|
||||
view.setLocation("/bar/foo.jsp");
|
||||
view.setAnchor("fragment");
|
||||
|
||||
Reference in New Issue
Block a user