提交 f0464e81 编写于 作者: R Rossen Stoyanchev

Add section on RFD + whitelist yml/properties/csv

Issue: SPR-13643
上级 b46a301e
......@@ -118,11 +118,15 @@ public class ContentNegotiationManagerFactoryBean
}
/**
* Add mappings from keys, 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
* strategy to work. The path extension strategy will also try
* {@link ServletContext#getMimeType} and JAF if it is present and is not
* suppressed via {@link #setUseJaf}.
* strategy to work. Any extensions explicitly registered here are also
* whitelisted for the purpose of Reflected File Download attack detection
* (see Spring Framework reference documentation for more details on RFD
* attack protection).
* <p>The path extension strategy will also try to use
* {@link ServletContext#getMimeType} and JAF (if present) to resolve path
* extensions. To change this behavior see the {@link #useJaf} property.
* @param mediaTypes media type mappings
* @see #addMediaType(String, MediaType)
* @see #addMediaTypes(Map)
......
......@@ -109,9 +109,13 @@ public class ContentNegotiationConfigurer {
/**
* 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
* strategy to work. The path extension strategy will also try
* {@link ServletContext#getMimeType} and JAF if it is present and is not
* suppressed via {@link #useJaf}.
* strategy to work. Any extensions explicitly registered here are also
* whitelisted for the purpose of Reflected File Download attack detection
* (see Spring Framework reference documentation for more details on RFD
* attack protection).
* <p>The path extension strategy will also try to use
* {@link ServletContext#getMimeType} and JAF (if present) to resolve path
* extensions. To change this behavior see the {@link #useJaf} property.
* @param extension the key to look up
* @param mediaType the media type
* @see #mediaTypes(Map)
......
......@@ -73,7 +73,9 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
/* Extensions associated with the built-in message converters */
private static final Set<String> WHITELISTED_EXTENSIONS = new HashSet<String>(Arrays.asList(
"txt", "text", "json", "xml", "atom", "rss", "png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));
"txt", "text", "yml", "properties", "csv",
"json", "xml", "atom", "rss",
"png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));
private final ContentNegotiationManager contentNegotiationManager;
......
......@@ -846,21 +846,75 @@ configuration. For more information on placeholders, see the javadocs of the
[[mvc-ann-requestmapping-suffix-pattern-match]]
==== Path Pattern Matching By Suffix
By default Spring MVC automatically performs `".{asterisk}"` suffix pattern matching so
that a controller mapped to `/person` is also implicitly mapped to `/person.{asterisk}`.
This allows indicating content types via file extensions, e.g. `/person.pdf`,
`/person.xml`, etc. A common pitfall however is when the last path segment of the
mapping is a URI variable, e.g. `/person/{id}`. While a request for `/person/1.json`
would correctly result in path variable id=1 and extension ".json", when the id
naturally contains a dot, e.g. `/person/joe@email.com` the result does not match
expectations. Clearly here ".com" is not a file extension.
==== Suffix Pattern Matching
By default Spring MVC performs `".{asterisk}"` suffix pattern matching so that a
controller mapped to `/person` is also implicitly mapped to `/person.{asterisk}`.
This makes it easy to request different representations of a resource through the
URL path (e.g. `/person.pdf`, `/person.xml`).
Suffix pattern matching can be turned off or restricted to a set of path extensions
explicitly registered for content negotiation purposes. This is generally
recommended to minimize ambiguity with common request mappings such as
`/person/{id}` where a dot might not represent a file extension, e.g.
`/person/joe@email.com` vs `/person/joe@email.com.json`. Furthermore as explained
in the note below suffix pattern matching as well as content negotiation may be
used in some circumstances to attempt malicious attacks and there are good
reasons to restrict them meaningfully.
See <<mvc-config-path-matching>> for suffix pattern matching configuration and
also <<mvc-config-content-negotiation>> for content negotiation configuration.
[[mvc-ann-requestmapping-rfd]]
==== Suffix Suffix Pattern Matching and RFD
Reflected file download (RFD) attack was first described in a
https://www.trustwave.com/Resources/SpiderLabs-Blog/Reflected-File-Download---A-New-Web-Attack-Vector/[paper by Trustwave]
in 2014. The attack is similar to XSS in that it relies on input
(e.g. query parameter, URI variable) being reflected in the response.
However instead of inserting JavaScript into HTML, an RFD attack relies on the
browser switching to perform a download and treating the response as an executable
script if double-clicked based on the file extension (e.g. .bat, .cmd).
In Spring MVC `@ResponseBody` and `ResponseEntity` methods are at risk because
they can render different content types which clients can request including
via URL path extensions. Note however that neither disabling suffix pattern matching
nor disabling the use of path extensions for content negotiation purposes alone
are effective at preventing RFD attacks.
For comprehensive protection against RFD, prior to rendering the response body
Spring MVC adds a `Content-Disposition:attachment;filename=f.txt` header to
suggest a fixed and safe download file filename. This is done only if the URL
path contains a file extension that is neither whitelisted nor explicitly
registered for content negotiation purposes. However it may potentially have
side effects when URLs are typed directly into a browser.
Many common path extensions are whitelisted by
default. Furthermore REST API calls are typically not meant to be used as URLs
directly in browsers. Nevertheless applications that use custom
`HttpMessageConverter` implementations can explicitly register file extensions
for content negotiation and the Content-Disposition header will not be added
for such extensions. See <<mvc-config-content-negotiation>>.
[NOTE]
====
This was originally introduced as part of work for
http://pivotal.io/security/cve-2015-5211[CVE-2015-5211].
Below are additional recommendations from the report:
* Encode rather than escape JSON responses. This is also an OWASP XSS recommendation.
For an example of how to do that with Spring see https://github.com/rwinch/spring-jackson-owasp[spring-jackson-owasp].
* Configure suffix pattern matching to be turned off or restricted to explicitly
registered suffixes only.
* Configure content negotiation with the properties “useJaf” and “ignoreUknownPathExtension”
set to false which would result in a 406 response for URLs with unknown extensions.
Note however that this may not be an option if URLs are naturally expected to have
a dot towards the end.
* Add `X-Content-Type-Options: nosniff` header to responses. Spring Security 4 does
this by default.
====
The proper way to address this is to configure Spring MVC to only do suffix pattern
matching against file extensions registered for content negotiation purposes.
For more on this, first see <<mvc-config-content-negotiation>> and then
<<mvc-config-path-matching>> showing how to enable suffix pattern matching
along with how to use registered suffix patterns only.
......@@ -4837,26 +4891,19 @@ And in XML use the `<mvc:interceptors>` element:
[[mvc-config-content-negotiation]]
=== Content Negotiation
You can configure how Spring MVC determines the requested media types from the client
for request mapping as well as for content negotiation purposes. The available options
are to check the file extension in the request URI, the "Accept" header, a request
parameter, as well as to fall back on a default content type. By default, file extension
in the request URI is checked first and the "Accept" header is checked next.
For file extensions in the request URI, the MVC Java config and the MVC namespace,
automatically register extensions such as `.json`, `.xml`, `.rss`, and `.atom` if the
corresponding dependencies such as Jackson, JAXB2, or Rome are present on the classpath.
Additional extensions may be not need to be registered explicitly if they can be
discovered via `ServletContext.getMimeType(String)` or the __Java Activation Framework__
(see `javax.activation.MimetypesFileTypeMap`). You can register more extensions with the
{api-spring-framework}/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.html#setUseRegisteredSuffixPatternMatch(boolean)[setUseRegisteredSuffixPatternMatch
method].
The introduction of `ContentNegotiationManager` also enables selective suffix pattern
matching for incoming requests. For more details, see its javadocs.
Below is an example of customizing content negotiation options through the MVC Java
config:
You can configure how Spring MVC determines the requested media types from the request.
The available options are to check the URL path for a file extension, check the
"Accept" header, a specific query parameter, or to fall back on a default content
type when nothing is requested. By default the path extension in the request URI
is checked first and the "Accept" header is checked second.
The MVC Java config and the MVC namespace register `json`, `xml`, `rss`, `atom` by
default if corresponding dependencies are on the classpath. Additional
path extension-to-media type mappings may also be registered explicitly and that
also has the effect of whitelisting them as safe extensions for the purpose of RFD
attack detection (see <<mvc-ann-requestmapping-rfd>> for more detail).
Below is an example of customizing content negotiation options through the MVC Java config:
[source,java,indent=0]
[subs="verbatim,quotes"]
......@@ -4867,7 +4914,7 @@ config:
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).favorParameter(true);
configurer.mediaType("json", MediaType.APPLICATION_JSON);
}
}
----
......@@ -4882,8 +4929,6 @@ that in turn can be created with a `ContentNegotiationManagerFactoryBean`:
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false"/>
<property name="favorParameter" value="true"/>
<property name="mediaTypes">
<value>
json=application/json
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册