Commit 1f26a031 authored by Brian Clozel's avatar Brian Clozel

Sanitize inputs in default reactive HTML error view

This commit uses HTML escaping to sanitize error inputs that are
displayed in the default reactive HTML error view.

Fixes gh-11582
parent 381d759e
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -38,6 +38,7 @@ import org.springframework.web.reactive.function.server.ServerRequest; ...@@ -38,6 +38,7 @@ import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.HtmlUtils;
/** /**
* Abstract base class for {@link ErrorWebExceptionHandler} implementations. * Abstract base class for {@link ErrorWebExceptionHandler} implementations.
...@@ -191,9 +192,11 @@ public abstract class AbstractErrorWebExceptionHandler ...@@ -191,9 +192,11 @@ public abstract class AbstractErrorWebExceptionHandler
.append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>") .append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>")
.append("<div id='created'>").append(timestamp.toString()) .append("<div id='created'>").append(timestamp.toString())
.append("</div>").append("<div>There was an unexpected error (type=") .append("</div>").append("<div>There was an unexpected error (type=")
.append(error.get("error")).append(", status=") .append(HtmlUtils.htmlEscape(error.get("error").toString())).append(", status=")
.append(error.get("status")).append(").</div>").append("<div>") .append(HtmlUtils.htmlEscape(error.get("status").toString()))
.append(error.get("message")).append("</div>").append("</body></html>"); .append(").</div>").append("<div>")
.append(HtmlUtils.htmlEscape(error.get("message").toString()))
.append("</div>").append("</body></html>");
return responseBody.syncBody(builder.toString()); return responseBody.syncBody(builder.toString());
} }
......
...@@ -220,6 +220,27 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -220,6 +220,27 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
}); });
} }
@Test
public void escapeHtmlInDefaultErrorView() throws Exception {
this.contextRunner
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/")
.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build();
String body = client.get().uri("/html").accept(MediaType.TEXT_HTML)
.exchange().expectStatus()
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectHeader()
.contentType(MediaType.TEXT_HTML).expectBody(String.class)
.returnResult().getResponseBody();
assertThat(body).contains("Whitelabel Error Page")
.doesNotContain("<script>")
.contains("&lt;script&gt;");
this.output.expect(
allOf(containsString("Failed to handle request [GET /html]"),
containsString("IllegalStateException")));
});
}
@Test @Test
public void responseCommitted() throws Exception { public void responseCommitted() throws Exception {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
...@@ -253,6 +274,11 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -253,6 +274,11 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
Mono.error(new IllegalStateException("already committed!"))); Mono.error(new IllegalStateException("already committed!")));
} }
@GetMapping("/html")
public String htmlEscape() {
throw new IllegalStateException("<script>");
}
@PostMapping(path = "/bind", produces = "application/json") @PostMapping(path = "/bind", produces = "application/json")
@ResponseBody @ResponseBody
public String bodyValidation(@Valid @RequestBody DummyBody body) { public String bodyValidation(@Valid @RequestBody DummyBody body) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment