Skip to content

Commit 652e5c5

Browse files
committed
Disable CORS credentials by default
Access-Control-Allow-Credentials CORS header, used to allow cookies with CORS requests, is not set to true anymore by default when enabling CORS with @crossorigin or global CORS configuration in order to provide a more secured default CORS configuration. The related allowCredentials property now requires to be set to true explicitly in order to support cookies with CORS requests. Issue: SPR-16130
1 parent 93f17da commit 652e5c5

File tree

10 files changed

+46
-33
lines changed

10 files changed

+46
-33
lines changed

spring-web/src/main/java/org/springframework/web/bind/annotation/CrossOrigin.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/**
2929
* Marks the annotated method or type as permitting cross origin requests.
3030
*
31-
* <p>By default all origins and headers are permitted, credentials are allowed,
31+
* <p>By default all origins and headers are permitted, credentials are not allowed,
3232
* and the maximum age is set to 1800 seconds (30 minutes). The list of HTTP
3333
* methods is set to the methods on the {@code @RequestMapping} if not
3434
* explicitly set on {@code @CrossOrigin}.
@@ -64,7 +64,7 @@
6464
* @deprecated as of Spring 5.0, in favor of using {@link CorsConfiguration#applyPermitDefaultValues}
6565
*/
6666
@Deprecated
67-
boolean DEFAULT_ALLOW_CREDENTIALS = true;
67+
boolean DEFAULT_ALLOW_CREDENTIALS = false;
6868

6969
/**
7070
* @deprecated as of Spring 5.0, in favor of using {@link CorsConfiguration#applyPermitDefaultValues}
@@ -118,12 +118,13 @@
118118

119119
/**
120120
* Whether the browser should include any cookies associated with the
121-
* domain of the request being annotated.
122-
* <p>Set to {@code "false"} if such cookies should not included.
123-
* An empty string ({@code ""}) means <em>undefined</em>.
124-
* {@code "true"} means that the pre-flight response will include the header
125-
* {@code Access-Control-Allow-Credentials=true}.
126-
* <p>If undefined, credentials are allowed.
121+
* domain of the request being annotated. Be aware that enabling this option could
122+
* increase the surface attack of the web application (for example via exposing
123+
* sensitive user-specific information like CSRF tokens).
124+
* <p>Set to {@code "true"} means that the pre-flight response will include the header
125+
* {@code Access-Control-Allow-Credentials=true} so such cookies should be included.
126+
* <p>If undefined or set to {@code "false"}, such header is not included and
127+
* credentials are not allowed.
127128
*/
128129
String allowCredentials() default "";
129130

spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,6 @@ public Long getMaxAge() {
324324
* <li>Allow all origins, i.e. {@code "*"}.</li>
325325
* <li>Allow "simple" methods {@code GET}, {@code HEAD} and {@code POST}.</li>
326326
* <li>Allow all headers.</li>
327-
* <li>Allow credentials.</li>
328327
* <li>Set max age to 1800 seconds (30 minutes).</li>
329328
* </ul>
330329
*/
@@ -339,9 +338,6 @@ public CorsConfiguration applyPermitDefaultValues() {
339338
if (this.allowedHeaders == null) {
340339
this.addAllowedHeader(ALL);
341340
}
342-
if (this.allowCredentials == null) {
343-
this.setAllowCredentials(true);
344-
}
345341
if (this.maxAge == null) {
346342
this.setMaxAge(1800L);
347343
}

spring-webflux/src/main/java/org/springframework/web/reactive/config/CorsRegistration.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,10 @@ public CorsRegistration maxAge(long maxAge) {
113113
}
114114

115115
/**
116-
* Whether user credentials are supported.
117-
* <p>By default this is set to {@code true} in which case user credentials
118-
* are supported.
116+
* Whether user credentials are supported. Be aware that enabling this option
117+
* could increase the surface attack of the web application (for example via
118+
* exposing sensitive user-specific information like CSRF tokens).
119+
* <p>By default credentials are not allowed.
119120
*/
120121
public CorsRegistration allowCredentials(boolean allowCredentials) {
121122
this.config.setAllowCredentials(allowCredentials);

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CrossOriginAnnotationIntegrationTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ public void actualPostRequestWithoutAnnotation() throws Exception {
104104
public void actualRequestWithDefaultAnnotation() throws Exception {
105105
ResponseEntity<String> entity = performGet("/default", this.headers, String.class);
106106
assertEquals(HttpStatus.OK, entity.getStatusCode());
107-
assertEquals("http://site1.com", entity.getHeaders().getAccessControlAllowOrigin());
108-
assertEquals(true, entity.getHeaders().getAccessControlAllowCredentials());
107+
assertEquals("*", entity.getHeaders().getAccessControlAllowOrigin());
108+
assertEquals(false, entity.getHeaders().getAccessControlAllowCredentials());
109109
assertEquals("default", entity.getBody());
110110
}
111111

@@ -114,9 +114,9 @@ public void preflightRequestWithDefaultAnnotation() throws Exception {
114114
this.headers.add(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
115115
ResponseEntity<Void> entity = performOptions("/default", this.headers, Void.class);
116116
assertEquals(HttpStatus.OK, entity.getStatusCode());
117-
assertEquals("http://site1.com", entity.getHeaders().getAccessControlAllowOrigin());
117+
assertEquals("*", entity.getHeaders().getAccessControlAllowOrigin());
118118
assertEquals(1800, entity.getHeaders().getAccessControlMaxAge());
119-
assertEquals(true, entity.getHeaders().getAccessControlAllowCredentials());
119+
assertEquals(false, entity.getHeaders().getAccessControlAllowCredentials());
120120
}
121121

122122
@Test

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/GlobalCorsConfigIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ protected RestTemplate initRestTemplate() {
7878
public void actualRequestWithCorsEnabled() throws Exception {
7979
ResponseEntity<String> entity = performGet("/cors", this.headers, String.class);
8080
assertEquals(HttpStatus.OK, entity.getStatusCode());
81-
assertEquals("http://localhost:9000", entity.getHeaders().getAccessControlAllowOrigin());
81+
assertEquals("*", entity.getHeaders().getAccessControlAllowOrigin());
8282
assertEquals("cors", entity.getBody());
8383
}
8484

@@ -106,7 +106,7 @@ public void preFlightRequestWithCorsEnabled() throws Exception {
106106
this.headers.add(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
107107
ResponseEntity<String> entity = performOptions("/cors", this.headers, String.class);
108108
assertEquals(HttpStatus.OK, entity.getStatusCode());
109-
assertEquals("http://localhost:9000", entity.getHeaders().getAccessControlAllowOrigin());
109+
assertEquals("*", entity.getHeaders().getAccessControlAllowOrigin());
110110
}
111111

112112
@Test

spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/CorsRegistration.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@ public CorsRegistration maxAge(long maxAge) {
115115
}
116116

117117
/**
118-
* Whether user credentials are supported.
119-
* <p>By default this is set to {@code true} in which case user credentials
120-
* are supported.
118+
* Whether user credentials are supported. Be aware that enabling this option
119+
* could increase the surface attack of the web application (for example via
120+
* exposing sensitive user-specific information like CSRF tokens).
121+
* <p>By default credentials are not allowed.
121122
*/
122123
public CorsRegistration allowCredentials(boolean allowCredentials) {
123124
this.config.setAllowCredentials(allowCredentials);

spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,7 @@ public void testCorsMinimal() throws Exception {
903903
assertArrayEquals(new String[]{"GET", "HEAD", "POST"}, config.getAllowedMethods().toArray());
904904
assertArrayEquals(new String[]{"*"}, config.getAllowedHeaders().toArray());
905905
assertNull(config.getExposedHeaders());
906-
assertTrue(config.getAllowCredentials());
906+
assertNull(config.getAllowCredentials());
907907
assertEquals(Long.valueOf(1800), config.getMaxAge());
908908
}
909909
}
@@ -933,7 +933,7 @@ public void testCors() throws Exception {
933933
assertArrayEquals(new String[]{"GET", "HEAD", "POST"}, config.getAllowedMethods().toArray());
934934
assertArrayEquals(new String[]{"*"}, config.getAllowedHeaders().toArray());
935935
assertNull(config.getExposedHeaders());
936-
assertTrue(config.getAllowCredentials());
936+
assertNull(config.getAllowCredentials());
937937
assertEquals(Long.valueOf(1800), config.getMaxAge());
938938
}
939939
}

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/CrossOriginTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public void defaultAnnotation() throws Exception {
126126
assertNotNull(config);
127127
assertArrayEquals(new String[] {"GET"}, config.getAllowedMethods().toArray());
128128
assertArrayEquals(new String[] {"*"}, config.getAllowedOrigins().toArray());
129-
assertTrue(config.getAllowCredentials());
129+
assertNull(config.getAllowCredentials());
130130
assertArrayEquals(new String[] {"*"}, config.getAllowedHeaders().toArray());
131131
assertTrue(CollectionUtils.isEmpty(config.getExposedHeaders()));
132132
assertEquals(new Long(1800), config.getMaxAge());
@@ -155,7 +155,7 @@ public void customOriginDefinedViaValueAttribute() throws Exception {
155155
CorsConfiguration config = getCorsConfiguration(chain, false);
156156
assertNotNull(config);
157157
assertEquals(Arrays.asList("http://example.com"), config.getAllowedOrigins());
158-
assertTrue(config.getAllowCredentials());
158+
assertNull(config.getAllowCredentials());
159159
}
160160

161161
@Test
@@ -166,7 +166,7 @@ public void customOriginDefinedViaPlaceholder() throws Exception {
166166
CorsConfiguration config = getCorsConfiguration(chain, false);
167167
assertNotNull(config);
168168
assertEquals(Arrays.asList("http://example.com"), config.getAllowedOrigins());
169-
assertTrue(config.getAllowCredentials());
169+
assertNull(config.getAllowCredentials());
170170
}
171171

172172
@Test
@@ -243,7 +243,7 @@ public void preFlightRequest() throws Exception {
243243
assertNotNull(config);
244244
assertArrayEquals(new String[] {"GET"}, config.getAllowedMethods().toArray());
245245
assertArrayEquals(new String[] {"*"}, config.getAllowedOrigins().toArray());
246-
assertTrue(config.getAllowCredentials());
246+
assertNull(config.getAllowCredentials());
247247
assertArrayEquals(new String[] {"*"}, config.getAllowedHeaders().toArray());
248248
assertTrue(CollectionUtils.isEmpty(config.getExposedHeaders()));
249249
assertEquals(new Long(1800), config.getMaxAge());

src/docs/asciidoc/web/webflux-cors.adoc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ implementation (https://github.com/spring-projects/spring-framework/blob/master/
2424
by default) in order to add the relevant CORS response headers (like `Access-Control-Allow-Origin`)
2525
based on the CORS configuration you have provided.
2626

27+
[NOTE]
28+
====
29+
Be aware that cookies are not allowed by default to avoid increasing the surface attack of
30+
the web application (for example via exposing sensitive user-specific information like
31+
CSRF tokens). Set `allowedCredentials` property to `true` in order to allow them.
32+
====
33+
2734

2835
[[webflux-cors-controller]]
2936
== @CrossOrigin
@@ -146,7 +153,7 @@ public class WebConfig implements WebFluxConfigurer {
146153
.allowedMethods("PUT", "DELETE")
147154
.allowedHeaders("header1", "header2", "header3")
148155
.exposedHeaders("header1", "header2")
149-
.allowCredentials(false).maxAge(3600);
156+
.allowCredentials(true).maxAge(3600);
150157
}
151158
}
152159
----

src/docs/asciidoc/web/webmvc-cors.adoc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ implementation (https://github.com/spring-projects/spring-framework/blob/master/
2727
by default) in order to add the relevant CORS response headers (like `Access-Control-Allow-Origin`)
2828
based on the CORS configuration you have provided.
2929

30+
[NOTE]
31+
====
32+
Be aware that cookies are not allowed by default to avoid increasing the surface attack of
33+
the web application (for example via exposing sensitive user-specific information like
34+
CSRF tokens). Set `allowedCredentials` property to `true` in order to allow them.
35+
====
36+
3037
[NOTE]
3138
====
3239
Since CORS requests are automatically dispatched, you *do not need* to change the
@@ -165,7 +172,7 @@ public class WebConfig implements WebMvcConfigurer {
165172
.allowedMethods("PUT", "DELETE")
166173
.allowedHeaders("header1", "header2", "header3")
167174
.exposedHeaders("header1", "header2")
168-
.allowCredentials(false).maxAge(3600);
175+
.allowCredentials(true).maxAge(3600);
169176
}
170177
}
171178
----
@@ -197,7 +204,7 @@ It is also possible to declare several CORS mappings with customized properties:
197204
allowed-origins="http://domain1.com, http://domain2.com"
198205
allowed-methods="GET, PUT"
199206
allowed-headers="header1, header2, header3"
200-
exposed-headers="header1, header2" allow-credentials="false"
207+
exposed-headers="header1, header2" allow-credentials="true"
201208
max-age="123" />
202209
203210
<mvc:mapping path="/resources/**"

0 commit comments

Comments
 (0)