Skip to content

Commit 70d4994

Browse files
Disable exception details on default error views
Prior to this commit, default error responses included the message from a handled exception. When the exception was a BindException, the error responses could also include an errors attribute containing the details of the binding failure. These details could leak information about the application. This commit removes the exception message and binding errors detail from error responses by default, and introduces a `server.error.include-details` property that can be used to cause these details to be included in the response. Fixes gh-20505
1 parent 8661474 commit 70d4994

File tree

25 files changed

+616
-179
lines changed

25 files changed

+616
-179
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/ManagementErrorEndpoint.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ public ManagementErrorEndpoint(ErrorAttributes errorAttributes) {
4747
@RequestMapping("${server.error.path:${error.path:/error}}")
4848
@ResponseBody
4949
public Map<String, Object> invoke(ServletWebRequest request) {
50-
return this.errorAttributes.getErrorAttributes(request, false);
50+
return this.errorAttributes.getErrorAttributes(request, false, false);
5151
}
5252

5353
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/WebMvcEndpointChildContextConfigurationIntegrationTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* Integration tests for {@link WebMvcEndpointChildContextConfiguration}.
4242
*
4343
* @author Phillip Webb
44+
* @author Scott Frederick
4445
*/
4546
class WebMvcEndpointChildContextConfigurationIntegrationTests {
4647

@@ -59,7 +60,8 @@ void errorPageAndErrorControllerAreUsed() {
5960
WebClient client = WebClient.create("http://localhost:" + port);
6061
ClientResponse response = client.get().uri("actuator/fail").accept(MediaType.APPLICATION_JSON)
6162
.exchange().block();
62-
assertThat(response.bodyToMono(String.class).block()).contains("message\":\"Epic Fail");
63+
assertThat(response.bodyToMono(String.class).block())
64+
.contains("message\":\"An error occurred while processing the request");
6365
});
6466
}
6567

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -61,6 +61,7 @@
6161
*
6262
* @param <T> the type of application context used by the tests
6363
* @author Andy Wilkinson
64+
* @author Scott Frederick
6465
*/
6566
public abstract class AbstractWebEndpointIntegrationTests<T extends ConfigurableApplicationContext & AnnotationConfigRegistry> {
6667

@@ -409,8 +410,10 @@ private void load(Consumer<T> contextCustomizer, String endpointPath,
409410
BiConsumer<ApplicationContext, WebTestClient> consumer) {
410411
T applicationContext = this.applicationContextSupplier.get();
411412
contextCustomizer.accept(applicationContext);
412-
applicationContext.getEnvironment().getPropertySources()
413-
.addLast(new MapPropertySource("test", Collections.singletonMap("endpointPath", endpointPath)));
413+
Map<String, Object> properties = new HashMap<>();
414+
properties.put("endpointPath", endpointPath);
415+
properties.put("server.error.include-details", "always");
416+
applicationContext.getEnvironment().getPropertySources().addLast(new MapPropertySource("test", properties));
414417
applicationContext.refresh();
415418
try {
416419
InetSocketAddress address = new InetSocketAddress(getPort(applicationContext));

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
* @author Michael Stummvoll
2525
* @author Stephane Nicoll
2626
* @author Vedran Pavic
27+
* @author Scott Frederick
2728
* @since 1.3.0
2829
*/
2930
public class ErrorProperties {
@@ -40,10 +41,15 @@ public class ErrorProperties {
4041
private boolean includeException;
4142

4243
/**
43-
* When to include a "stacktrace" attribute.
44+
* When to include the "trace" attribute.
4445
*/
4546
private IncludeStacktrace includeStacktrace = IncludeStacktrace.NEVER;
4647

48+
/**
49+
* When to include "message" and "errors" attributes.
50+
*/
51+
private IncludeDetails includeDetails = IncludeDetails.NEVER;
52+
4753
private final Whitelabel whitelabel = new Whitelabel();
4854

4955
public String getPath() {
@@ -70,6 +76,14 @@ public void setIncludeStacktrace(IncludeStacktrace includeStacktrace) {
7076
this.includeStacktrace = includeStacktrace;
7177
}
7278

79+
public IncludeDetails getIncludeDetails() {
80+
return this.includeDetails;
81+
}
82+
83+
public void setIncludeDetails(IncludeDetails includeDetails) {
84+
this.includeDetails = includeDetails;
85+
}
86+
7387
public Whitelabel getWhitelabel() {
7488
return this.whitelabel;
7589
}
@@ -96,6 +110,28 @@ public enum IncludeStacktrace {
96110

97111
}
98112

113+
/**
114+
* Include error details attributes options.
115+
*/
116+
public enum IncludeDetails {
117+
118+
/**
119+
* Never add error detail information.
120+
*/
121+
NEVER,
122+
123+
/**
124+
* Always add error detail information.
125+
*/
126+
ALWAYS,
127+
128+
/**
129+
* Add error details information when the "details" request parameter is "true".
130+
*/
131+
ON_DETAILS_PARAM
132+
133+
}
134+
99135
public static class Whitelabel {
100136

101137
/**

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/AbstractErrorWebExceptionHandler.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -54,6 +54,7 @@
5454
* Abstract base class for {@link ErrorWebExceptionHandler} implementations.
5555
*
5656
* @author Brian Clozel
57+
* @author Scott Frederick
5758
* @since 2.0.0
5859
* @see ErrorAttributes
5960
*/
@@ -131,10 +132,26 @@ public void setViewResolvers(List<ViewResolver> viewResolvers) {
131132
* views or JSON payloads.
132133
* @param request the source request
133134
* @param includeStackTrace whether to include the error stacktrace information
134-
* @return the error attributes as a Map.
135+
* @return the error attributes as a Map
136+
* @deprecated since 2.3.0 in favor of
137+
* {@link #getErrorAttributes(ServerRequest, boolean, boolean)}
135138
*/
139+
@Deprecated
136140
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
137-
return this.errorAttributes.getErrorAttributes(request, includeStackTrace);
141+
return this.errorAttributes.getErrorAttributes(request, includeStackTrace, false);
142+
}
143+
144+
/**
145+
* Extract the error attributes from the current request, to be used to populate error
146+
* views or JSON payloads.
147+
* @param request the source request
148+
* @param includeStackTrace whether to include the error stacktrace information
149+
* @param includeDetails whether to include message and errors attributes
150+
* @return the error attributes as a Map
151+
*/
152+
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace,
153+
boolean includeDetails) {
154+
return this.errorAttributes.getErrorAttributes(request, includeStackTrace, includeDetails);
138155
}
139156

140157
/**
@@ -152,7 +169,21 @@ protected Throwable getError(ServerRequest request) {
152169
* @return {@code true} if the error trace has been requested, {@code false} otherwise
153170
*/
154171
protected boolean isTraceEnabled(ServerRequest request) {
155-
String parameter = request.queryParam("trace").orElse("false");
172+
return getBooleanParameter(request, "trace");
173+
}
174+
175+
/**
176+
* Check whether the details attribute has been set on the given request.
177+
* @param request the source request
178+
* @return {@code true} if the error details have been requested, {@code false}
179+
* otherwise
180+
*/
181+
protected boolean isDetailsEnabled(ServerRequest request) {
182+
return getBooleanParameter(request, "details");
183+
}
184+
185+
private boolean getBooleanParameter(ServerRequest request, String parameterName) {
186+
String parameter = request.queryParam(parameterName).orElse("false");
156187
return !"false".equalsIgnoreCase(parameter);
157188
}
158189

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -71,6 +71,7 @@
7171
* payload.
7272
*
7373
* @author Brian Clozel
74+
* @author Scott Frederick
7475
* @since 2.0.0
7576
*/
7677
public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
@@ -113,7 +114,8 @@ protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes erro
113114
*/
114115
protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
115116
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.TEXT_HTML);
116-
Map<String, Object> error = getErrorAttributes(request, includeStackTrace);
117+
boolean includeDetails = isIncludeDetails(request, MediaType.TEXT_HTML);
118+
Map<String, Object> error = getErrorAttributes(request, includeStackTrace, includeDetails);
117119
int errorStatus = getHttpStatus(error);
118120
ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus).contentType(TEXT_HTML_UTF8);
119121
return Flux.just(getData(errorStatus).toArray(new String[] {}))
@@ -141,7 +143,8 @@ private List<String> getData(int errorStatus) {
141143
*/
142144
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
143145
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
144-
Map<String, Object> error = getErrorAttributes(request, includeStackTrace);
146+
boolean includeDetails = isIncludeDetails(request, MediaType.ALL);
147+
Map<String, Object> error = getErrorAttributes(request, includeStackTrace, includeDetails);
145148
return ServerResponse.status(getHttpStatus(error)).contentType(MediaType.APPLICATION_JSON)
146149
.body(BodyInserters.fromValue(error));
147150
}
@@ -163,6 +166,23 @@ protected boolean isIncludeStackTrace(ServerRequest request, MediaType produces)
163166
return false;
164167
}
165168

169+
/**
170+
* Determine if the message and errors attributes should be included.
171+
* @param request the source request
172+
* @param produces the media type produced (or {@code MediaType.ALL})
173+
* @return if the message and errors attributes should be included
174+
*/
175+
protected boolean isIncludeDetails(ServerRequest request, MediaType produces) {
176+
ErrorProperties.IncludeDetails include = this.errorProperties.getIncludeDetails();
177+
if (include == ErrorProperties.IncludeDetails.ALWAYS) {
178+
return true;
179+
}
180+
if (include == ErrorProperties.IncludeDetails.ON_DETAILS_PARAM) {
181+
return isDetailsEnabled(request);
182+
}
183+
return false;
184+
}
185+
166186
/**
167187
* Get the HTTP error status information from the error map.
168188
* @param errorAttributes the current error information

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/AbstractErrorController.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@
3838
*
3939
* @author Dave Syer
4040
* @author Phillip Webb
41+
* @author Scott Frederick
4142
* @since 1.3.0
4243
* @see ErrorAttributes
4344
*/
@@ -66,13 +67,35 @@ private List<ErrorViewResolver> sortErrorViewResolvers(List<ErrorViewResolver> r
6667
return sorted;
6768
}
6869

70+
/**
71+
* Returns a {@link Map} of the error attributes.
72+
* @param request the source request
73+
* @param includeStackTrace if stack trace elements should be included
74+
* @return the error attributes
75+
* @deprecated since 2.3.0 in favor of
76+
* {@link #getErrorAttributes(HttpServletRequest, boolean, boolean)}
77+
*/
78+
@Deprecated
6979
protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
80+
return this.getErrorAttributes(request, includeStackTrace, false);
81+
}
82+
83+
protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace,
84+
boolean includeDetails) {
7085
WebRequest webRequest = new ServletWebRequest(request);
71-
return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
86+
return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace, includeDetails);
7287
}
7388

7489
protected boolean getTraceParameter(HttpServletRequest request) {
75-
String parameter = request.getParameter("trace");
90+
return getBooleanParameter(request, "trace");
91+
}
92+
93+
protected boolean getDetailsParameter(HttpServletRequest request) {
94+
return getBooleanParameter(request, "details");
95+
}
96+
97+
protected boolean getBooleanParameter(HttpServletRequest request, String parameterName) {
98+
String parameter = request.getParameter(parameterName);
7699
if (parameter == null) {
77100
return false;
78101
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import javax.servlet.http.HttpServletResponse;
2525

2626
import org.springframework.boot.autoconfigure.web.ErrorProperties;
27+
import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeDetails;
2728
import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace;
2829
import org.springframework.boot.web.servlet.error.ErrorAttributes;
2930
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
@@ -47,6 +48,7 @@
4748
* @author Phillip Webb
4849
* @author Michael Stummvoll
4950
* @author Stephane Nicoll
51+
* @author Scott Frederick
5052
* @since 1.0.0
5153
* @see ErrorAttributes
5254
* @see ErrorProperties
@@ -87,8 +89,8 @@ public String getErrorPath() {
8789
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
8890
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
8991
HttpStatus status = getStatus(request);
90-
Map<String, Object> model = Collections
91-
.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
92+
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request,
93+
isIncludeStackTrace(request, MediaType.TEXT_HTML), isIncludeDetails(request, MediaType.TEXT_HTML)));
9294
response.setStatus(status.value());
9395
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
9496
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
@@ -100,7 +102,8 @@ public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
100102
if (status == HttpStatus.NO_CONTENT) {
101103
return new ResponseEntity<>(status);
102104
}
103-
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
105+
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL),
106+
isIncludeDetails(request, MediaType.ALL));
104107
return new ResponseEntity<>(body, status);
105108
}
106109

@@ -127,6 +130,23 @@ protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType prod
127130
return false;
128131
}
129132

133+
/**
134+
* Determine if the error details attributes should be included.
135+
* @param request the source request
136+
* @param produces the media type produced (or {@code MediaType.ALL})
137+
* @return if the error details attributes should be included
138+
*/
139+
protected boolean isIncludeDetails(HttpServletRequest request, MediaType produces) {
140+
IncludeDetails include = getErrorProperties().getIncludeDetails();
141+
if (include == IncludeDetails.ALWAYS) {
142+
return true;
143+
}
144+
if (include == IncludeDetails.ON_DETAILS_PARAM) {
145+
return getDetailsParameter(request);
146+
}
147+
return false;
148+
}
149+
130150
/**
131151
* Provide access to the error properties.
132152
* @return the error properties

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@
106106
"description": "Minimum \"Content-Length\" value that is required for compression to be performed.",
107107
"defaultValue": "2KB"
108108
},
109+
{
110+
"name": "server.error.include-details",
111+
"defaultValue": "never"
112+
},
109113
{
110114
"name": "server.error.include-stacktrace",
111115
"defaultValue": "never"

0 commit comments

Comments
 (0)