Add section on RFD + whitelist yml/properties/csv
Issue: SPR-13643
This commit is contained in:
		
							parent
							
								
									b46a301e8a
								
							
						
					
					
						commit
						f0464e8176
					
				|  | @ -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. | ||||
| 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. | ||||
| 
 | ||||
| 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 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). | ||||
| 
 | ||||
| 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: | ||||
| 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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue