Merge branch '5.2.x'
This commit is contained in:
commit
1984cfe9d7
|
@ -413,7 +413,7 @@ public class ReactiveAdapterRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code BlockHoundIntegration} for spring-core classes.
|
* {@code BlockHoundIntegration} for spring-core classes.
|
||||||
* <p>Whitelists the following:
|
* <p>Explicitly allow the following:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Reading class info via {@link LocalVariableTableParameterNameDiscoverer}.
|
* <li>Reading class info via {@link LocalVariableTableParameterNameDiscoverer}.
|
||||||
* <li>Locking within {@link ConcurrentReferenceHashMap}.
|
* <li>Locking within {@link ConcurrentReferenceHashMap}.
|
||||||
|
|
|
@ -196,7 +196,7 @@ public class ContentNegotiationManagerFactoryBean
|
||||||
* {@code ResourceHttpRequestHandler}.
|
* {@code ResourceHttpRequestHandler}.
|
||||||
* <li>Determine the media type of views rendered with
|
* <li>Determine the media type of views rendered with
|
||||||
* {@code ContentNegotiatingViewResolver}.
|
* {@code ContentNegotiatingViewResolver}.
|
||||||
* <li>Whitelist extensions for RFD attack detection (check the Spring
|
* <li>List safe extensions for RFD attack detection (check the Spring
|
||||||
* Framework reference docs for details).
|
* Framework reference docs for details).
|
||||||
* </ul>
|
* </ul>
|
||||||
* @param mediaTypes media type mappings
|
* @param mediaTypes media type mappings
|
||||||
|
|
|
@ -162,9 +162,9 @@ public class ContentNegotiationConfigurer {
|
||||||
* Add a mapping from a key, extracted from a path extension or a query
|
* Add a mapping from a key, extracted from a path extension or a query
|
||||||
* parameter, to a MediaType. This is required in order for the parameter
|
* parameter, to a MediaType. This is required in order for the parameter
|
||||||
* strategy to work. Any extensions explicitly registered here are also
|
* strategy to work. Any extensions explicitly registered here are also
|
||||||
* whitelisted for the purpose of Reflected File Download attack detection
|
* treated as safe for the purpose of Reflected File Download attack
|
||||||
* (see Spring Framework reference documentation for more details on RFD
|
* detection (see Spring Framework reference documentation for more details
|
||||||
* attack protection).
|
* on RFD attack protection).
|
||||||
* <p>The path extension strategy will also try to use
|
* <p>The path extension strategy will also try to use
|
||||||
* {@link ServletContext#getMimeType} and {@link MediaTypeFactory} to resolve path
|
* {@link ServletContext#getMimeType} and {@link MediaTypeFactory} to resolve path
|
||||||
* extensions. To change this behavior see the {@link #useRegisteredExtensionsOnly} property.
|
* extensions. To change this behavior see the {@link #useRegisteredExtensionsOnly} property.
|
||||||
|
|
|
@ -76,12 +76,12 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||||
implements HandlerMethodReturnValueHandler {
|
implements HandlerMethodReturnValueHandler {
|
||||||
|
|
||||||
/* Extensions associated with the built-in message converters */
|
/* Extensions associated with the built-in message converters */
|
||||||
private static final Set<String> WHITELISTED_EXTENSIONS = new HashSet<>(Arrays.asList(
|
private static final Set<String> SAFE_EXTENSIONS = new HashSet<>(Arrays.asList(
|
||||||
"txt", "text", "yml", "properties", "csv",
|
"txt", "text", "yml", "properties", "csv",
|
||||||
"json", "xml", "atom", "rss",
|
"json", "xml", "atom", "rss",
|
||||||
"png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));
|
"png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));
|
||||||
|
|
||||||
private static final Set<String> WHITELISTED_MEDIA_BASE_TYPES = new HashSet<>(
|
private static final Set<String> SAFE_MEDIA_BASE_TYPES = new HashSet<>(
|
||||||
Arrays.asList("audio", "image", "video"));
|
Arrays.asList("audio", "image", "video"));
|
||||||
|
|
||||||
private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES =
|
private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES =
|
||||||
|
@ -133,7 +133,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||||
|
|
||||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||||
this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
|
this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
|
||||||
this.safeExtensions.addAll(WHITELISTED_EXTENSIONS);
|
this.safeExtensions.addAll(SAFE_EXTENSIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -406,8 +406,8 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the path has a file extension and whether the extension is
|
* Check if the path has a file extension and whether the extension is either
|
||||||
* either {@link #WHITELISTED_EXTENSIONS whitelisted} or explicitly
|
* on the list of {@link #SAFE_EXTENSIONS safe extensions} or explicitly
|
||||||
* {@link ContentNegotiationManager#getAllFileExtensions() registered}.
|
* {@link ContentNegotiationManager#getAllFileExtensions() registered}.
|
||||||
* If not, and the status is in the 2xx range, a 'Content-Disposition'
|
* If not, and the status is in the 2xx range, a 'Content-Disposition'
|
||||||
* header with a safe attachment file name ("f.txt") is added to prevent
|
* header with a safe attachment file name ("f.txt") is added to prevent
|
||||||
|
@ -491,7 +491,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean safeMediaType(MediaType mediaType) {
|
private boolean safeMediaType(MediaType mediaType) {
|
||||||
return (WHITELISTED_MEDIA_BASE_TYPES.contains(mediaType.getType()) ||
|
return (SAFE_MEDIA_BASE_TYPES.contains(mediaType.getType()) ||
|
||||||
mediaType.getSubtype().endsWith("+xml"));
|
mediaType.getSubtype().endsWith("+xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ public class RequestResponseBodyMethodProcessorTests {
|
||||||
Collections.singletonList(new StringHttpMessageConverter()),
|
Collections.singletonList(new StringHttpMessageConverter()),
|
||||||
factory.getObject());
|
factory.getObject());
|
||||||
|
|
||||||
assertContentDisposition(processor, false, "/hello.json", "whitelisted extension");
|
assertContentDisposition(processor, false, "/hello.json", "safe extension");
|
||||||
assertContentDisposition(processor, false, "/hello.pdf", "registered extension");
|
assertContentDisposition(processor, false, "/hello.pdf", "registered extension");
|
||||||
assertContentDisposition(processor, true, "/hello.dataless", "unknown extension");
|
assertContentDisposition(processor, true, "/hello.dataless", "unknown extension");
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@ public class RequestResponseBodyMethodProcessorTests {
|
||||||
assertContentDisposition(processor, false, "/hello.json;a=b", "path param shouldn't cause issue");
|
assertContentDisposition(processor, false, "/hello.json;a=b", "path param shouldn't cause issue");
|
||||||
assertContentDisposition(processor, true, "/hello.json;a=b;setup.dataless", "unknown ext in path params");
|
assertContentDisposition(processor, true, "/hello.json;a=b;setup.dataless", "unknown ext in path params");
|
||||||
assertContentDisposition(processor, true, "/hello.dataless;a=b;setup.json", "unknown ext in filename");
|
assertContentDisposition(processor, true, "/hello.dataless;a=b;setup.json", "unknown ext in filename");
|
||||||
assertContentDisposition(processor, false, "/hello.json;a=b;setup.json", "whitelisted extensions");
|
assertContentDisposition(processor, false, "/hello.json;a=b;setup.json", "safe extensions");
|
||||||
|
|
||||||
// encoded dot
|
// encoded dot
|
||||||
assertContentDisposition(processor, true, "/hello%2Edataless;a=b;setup.json", "encoded dot in filename");
|
assertContentDisposition(processor, true, "/hello%2Edataless;a=b;setup.json", "encoded dot in filename");
|
||||||
|
|
|
@ -1725,11 +1725,11 @@ lower the risk but are not sufficient to prevent RFD attacks.
|
||||||
|
|
||||||
To prevent RFD attacks, prior to rendering the response body, Spring MVC adds a
|
To prevent RFD attacks, prior to rendering the response body, Spring MVC adds a
|
||||||
`Content-Disposition:inline;filename=f.txt` header to suggest a fixed and safe download
|
`Content-Disposition:inline;filename=f.txt` header to suggest a fixed and safe download
|
||||||
file. This is done only if the URL path contains a file extension that is neither whitelisted
|
file. This is done only if the URL path contains a file extension that is neither
|
||||||
nor explicitly registered for content negotiation. However, it can potentially have
|
allowed as safe nor explicitly registered for content negotiation. However, it can
|
||||||
side effects when URLs are typed directly into a browser.
|
potentially have side effects when URLs are typed directly into a browser.
|
||||||
|
|
||||||
Many common path extensions are whitelisted by default. Applications with custom
|
Many common path extensions are allowed as safe by default. Applications with custom
|
||||||
`HttpMessageConverter` implementations can explicitly register file extensions for content
|
`HttpMessageConverter` implementations can explicitly register file extensions for content
|
||||||
negotiation to avoid having a `Content-Disposition` header added for those extensions.
|
negotiation to avoid having a `Content-Disposition` header added for those extensions.
|
||||||
See <<mvc-config-content-negotiation>>.
|
See <<mvc-config-content-negotiation>>.
|
||||||
|
|
Loading…
Reference in New Issue