mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Apply HTML escaping to timestamp attribute in Whitelabel error page
See gh-50205 Signed-off-by: Daeho Kwon <trewq231@naver.com>
This commit is contained in:
committed by
Stéphane Nicoll
parent
f280d12729
commit
f273f5ec35
+3
-4
@@ -17,7 +17,6 @@
|
||||
package org.springframework.boot.autoconfigure.web.reactive.error;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -237,17 +236,17 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
protected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody,
|
||||
Map<String, Object> error) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Date timestamp = (Date) error.get("timestamp");
|
||||
Object timestamp = error.get("timestamp");
|
||||
Object message = error.get("message");
|
||||
Object trace = error.get("trace");
|
||||
Object requestId = error.get("requestId");
|
||||
builder.append("<html><body><h1>Whitelabel Error Page</h1>")
|
||||
.append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>")
|
||||
.append("<div id='created'>")
|
||||
.append(timestamp)
|
||||
.append(htmlEscape(timestamp))
|
||||
.append("</div>")
|
||||
.append("<div>[")
|
||||
.append(requestId)
|
||||
.append(htmlEscape(requestId))
|
||||
.append("] There was an unexpected error (type=")
|
||||
.append(htmlEscape(error.get("error")))
|
||||
.append(", status=")
|
||||
|
||||
+1
-1
@@ -213,7 +213,7 @@ public class ErrorMvcAutoConfiguration {
|
||||
builder.append("<html><body><h1>Whitelabel Error Page</h1>")
|
||||
.append("<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
|
||||
.append("<div id='created'>")
|
||||
.append(timestamp)
|
||||
.append(htmlEscape(timestamp))
|
||||
.append("</div>")
|
||||
.append("<div>There was an unexpected error (type=")
|
||||
.append(htmlEscape(model.get("error")))
|
||||
|
||||
+43
@@ -460,6 +460,27 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void escapeHtmlInTimestampAndRequestIdAttributes() {
|
||||
this.contextRunner.withPropertyValues("spring.mustache.prefix=classpath:/unknown/")
|
||||
.withUserConfiguration(CustomErrorAttributesWithHtmlInTimestampAndRequestId.class)
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
String body = client.get()
|
||||
.uri("/")
|
||||
.accept(MediaType.TEXT_HTML)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectHeader()
|
||||
.contentType(TEXT_HTML_UTF8)
|
||||
.expectBody(String.class)
|
||||
.returnResult()
|
||||
.getResponseBody();
|
||||
assertThat(body).doesNotContain("<script>").contains("<script>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExceptionWithNullMessage() {
|
||||
this.contextRunner.withPropertyValues("spring.mustache.prefix=classpath:/unknown/").run((context) -> {
|
||||
@@ -781,4 +802,26 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomErrorAttributesWithHtmlInTimestampAndRequestId {
|
||||
|
||||
@Bean
|
||||
ErrorAttributes errorAttributes() {
|
||||
return new DefaultErrorAttributes() {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(ServerRequest request,
|
||||
ErrorAttributeOptions options) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>(
|
||||
super.getErrorAttributes(request, options));
|
||||
attributes.put("timestamp", "<script>alert('xss')</script>");
|
||||
attributes.put("requestId", "<script>alert('xss')</script>");
|
||||
return attributes;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.web.servlet.error;
|
||||
import java.time.Clock;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@@ -84,6 +85,24 @@ class ErrorMvcAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void renderEscapesHtmlInTimestampAttribute() {
|
||||
this.contextRunner.run((context) -> {
|
||||
View errorView = context.getBean("error", View.class);
|
||||
ErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);
|
||||
DispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException("Exception message"),
|
||||
false);
|
||||
Map<String, Object> attributes = errorAttributes.getErrorAttributes(webRequest, withAllOptions());
|
||||
attributes.put("timestamp", "<script>alert('xss')</script>");
|
||||
HttpServletResponse response = webRequest.getResponse();
|
||||
assertThat(response).isNotNull();
|
||||
errorView.render(attributes, webRequest.getRequest(), response);
|
||||
String responseString = ((MockHttpServletResponse) response).getContentAsString();
|
||||
assertThat(responseString).contains("<script>alert('xss')</script>")
|
||||
.doesNotContain("<script>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void renderWhenAlreadyCommittedLogsMessage(CapturedOutput output) {
|
||||
this.contextRunner.run((context) -> {
|
||||
|
||||
Reference in New Issue
Block a user