diff --git a/java/org/apache/catalina/filters/CorsFilter.java b/java/org/apache/catalina/filters/CorsFilter.java
index 0a18fd2ee..514f6487a 100644
--- a/java/org/apache/catalina/filters/CorsFilter.java
+++ b/java/org/apache/catalina/filters/CorsFilter.java
@@ -278,17 +278,14 @@ protected void handleSimpleCORS(final HttpServletRequest request,
// Section 6.1.3
// Add a single Access-Control-Allow-Origin header.
- if (anyOriginAllowed && !supportsCredentials) {
- // If resource doesn't support credentials and if any origin is
- // allowed
- // to make CORS request, return header with '*'.
+ if (anyOriginAllowed) {
+ // If any origin is allowed, return header with '*'.
response.addHeader(
CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
"*");
} else {
- // If the resource supports credentials add a single
- // Access-Control-Allow-Origin header, with the value of the Origin
- // header as value.
+ // Add a single Access-Control-Allow-Origin header, with the value
+ // of the Origin header as value.
response.addHeader(
CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
origin);
@@ -804,6 +801,10 @@ private void parseAndStore(final String allowedOrigins,
// For any value other then 'true' this will be false.
this.supportsCredentials = Boolean.parseBoolean(supportsCredentials);
+ if (this.supportsCredentials && this.anyOriginAllowed) {
+ throw new ServletException(sm.getString("corsFilter.invalidSupportsCredentials"));
+ }
+
try {
if (!preflightMaxAge.isEmpty()) {
this.preflightMaxAge = Long.parseLong(preflightMaxAge);
@@ -1163,7 +1164,7 @@ protected enum CORSRequestType {
/**
* By default, all origins are allowed to make requests.
*/
- public static final String DEFAULT_ALLOWED_ORIGINS = "*";
+ public static final String DEFAULT_ALLOWED_ORIGINS = "";
/**
* By default, following methods are supported: GET, POST, HEAD and OPTIONS.
@@ -1179,7 +1180,7 @@ protected enum CORSRequestType {
/**
* By default, support credentials is turned on.
*/
- public static final String DEFAULT_SUPPORTS_CREDENTIALS = "true";
+ public static final String DEFAULT_SUPPORTS_CREDENTIALS = "false";
/**
* By default, following headers are supported:
diff --git a/java/org/apache/catalina/filters/LocalStrings.properties b/java/org/apache/catalina/filters/LocalStrings.properties
index 5c4c792f8..921f10145 100644
--- a/java/org/apache/catalina/filters/LocalStrings.properties
+++ b/java/org/apache/catalina/filters/LocalStrings.properties
@@ -14,6 +14,8 @@
# limitations under the License.
addDefaultCharset.unsupportedCharset=Specified character set [{0}] is not supported
+
+corsFilter.invalidSupportsCredentials=It is not allowed to configure supportsCredentials=[true] when allowedOrigins=[*]
corsFilter.invalidPreflightMaxAge=Unable to parse preflightMaxAge
corsFilter.nullRequest=HttpServletRequest object is null
corsFilter.nullRequestType=CORSRequestType object is null
diff --git a/test/org/apache/catalina/filters/TestCorsFilter.java b/test/org/apache/catalina/filters/TestCorsFilter.java
index 8f69111aa..0cda04054 100644
--- a/test/org/apache/catalina/filters/TestCorsFilter.java
+++ b/test/org/apache/catalina/filters/TestCorsFilter.java
@@ -52,8 +52,7 @@ public void testDoFilterSimpleGET() throws IOException, ServletException {
corsFilter.doFilter(request, response, filterChain);
Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- "https://www.apache.org"));
+ CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
Assert.assertTrue(((Boolean) request.getAttribute(
CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
Assert.assertTrue(request.getAttribute(
@@ -85,8 +84,7 @@ public void testDoFilterSimplePOST() throws IOException, ServletException {
corsFilter.doFilter(request, response, filterChain);
Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- "https://www.apache.org"));
+ CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
Assert.assertTrue(((Boolean) request.getAttribute(
CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
Assert.assertTrue(request.getAttribute(
@@ -117,8 +115,7 @@ public void testDoFilterSimpleHEAD() throws IOException, ServletException {
corsFilter.doFilter(request, response, filterChain);
Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- "https://www.apache.org"));
+ CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
Assert.assertTrue(((Boolean) request.getAttribute(
CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
Assert.assertTrue(request.getAttribute(
@@ -163,41 +160,15 @@ public void testDoFilterSimpleSpecificHeader() throws IOException,
}
/*
- * Tests the presence of the origin (and not '*') in the response, when
- * supports credentials is enabled alongwith any origin, '*'.
+ * Tests the that supports credentials may not be enabled with any origin,
+ * '*'.
*
- * @throws IOException
* @throws ServletException
*/
- @Test
- public void testDoFilterSimpleAnyOriginAndSupportsCredentials()
- throws IOException, ServletException {
- TesterHttpServletRequest request = new TesterHttpServletRequest();
- request.setHeader(CorsFilter.REQUEST_HEADER_ORIGIN,
- TesterFilterConfigs.HTTPS_WWW_APACHE_ORG);
- request.setMethod("GET");
- TesterHttpServletResponse response = new TesterHttpServletResponse();
-
+ @Test(expected=ServletException.class)
+ public void testDoFilterSimpleAnyOriginAndSupportsCredentials() throws ServletException {
CorsFilter corsFilter = new CorsFilter();
- corsFilter.init(TesterFilterConfigs
- .getFilterConfigAnyOriginAndSupportsCredentials());
- corsFilter.doFilter(request, response, filterChain);
-
- Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- TesterFilterConfigs.HTTPS_WWW_APACHE_ORG));
- Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS)
- .equals(
- "true"));
- Assert.assertTrue(((Boolean) request.getAttribute(
- CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
- Assert.assertTrue(request.getAttribute(
- CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN).equals(
- TesterFilterConfigs.HTTPS_WWW_APACHE_ORG));
- Assert.assertTrue(request.getAttribute(
- CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE).equals(
- CorsFilter.CORSRequestType.SIMPLE.name().toLowerCase(Locale.ENGLISH)));
+ corsFilter.init(TesterFilterConfigs.getFilterConfigAnyOriginAndSupportsCredentials());
}
/*
@@ -258,8 +229,7 @@ public void testDoFilterSimpleWithExposedHeaders() throws IOException,
corsFilter.doFilter(request, response, filterChain);
Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- "https://www.apache.org"));
+ CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
Assert.assertTrue(response.getHeader(
CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS)
.equals(TesterFilterConfigs.EXPOSED_HEADERS));
@@ -707,9 +677,8 @@ public void testInitDefaultFilterConfig() throws IOException,
corsFilter.init(null);
corsFilter.doFilter(request, response, filterChain);
- Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- "https://www.apache.org"));
+ Assert.assertNull(response.getHeader(
+ CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN));
Assert.assertTrue(((Boolean) request.getAttribute(
CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
Assert.assertTrue(request.getAttribute(
@@ -1392,7 +1361,7 @@ public void testWithFilterConfig() throws ServletException {
Assert.assertTrue(corsFilter.getAllowedOrigins().size() == 0);
Assert.assertTrue(corsFilter.isAnyOriginAllowed());
Assert.assertTrue(corsFilter.getExposedHeaders().size() == 0);
- Assert.assertTrue(corsFilter.isSupportsCredentials());
+ Assert.assertFalse(corsFilter.isSupportsCredentials());
Assert.assertTrue(corsFilter.getPreflightMaxAge() == 1800);
}
@@ -1428,9 +1397,9 @@ public void testWithStringParserNull() throws ServletException {
Assert.assertTrue(corsFilter.getAllowedHttpHeaders().size() == 6);
Assert.assertTrue(corsFilter.getAllowedHttpMethods().size() == 4);
Assert.assertTrue(corsFilter.getAllowedOrigins().size() == 0);
- Assert.assertTrue(corsFilter.isAnyOriginAllowed());
+ Assert.assertFalse(corsFilter.isAnyOriginAllowed());
Assert.assertTrue(corsFilter.getExposedHeaders().size() == 0);
- Assert.assertTrue(corsFilter.isSupportsCredentials());
+ Assert.assertFalse(corsFilter.isSupportsCredentials());
Assert.assertTrue(corsFilter.getPreflightMaxAge() == 1800);
}
@@ -1534,8 +1503,7 @@ public void testDecorateRequestDisabled() throws IOException,
corsFilter.doFilter(request, response, filterChain);
Assert.assertTrue(response.getHeader(
- CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
- "https://www.apache.org"));
+ CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
Assert.assertNull(request
.getAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST));
Assert.assertNull(request
diff --git a/test/org/apache/catalina/filters/TesterFilterConfigs.java b/test/org/apache/catalina/filters/TesterFilterConfigs.java
index 941d8949d..cb3d04f81 100644
--- a/test/org/apache/catalina/filters/TesterFilterConfigs.java
+++ b/test/org/apache/catalina/filters/TesterFilterConfigs.java
@@ -36,12 +36,13 @@ public class TesterFilterConfigs {
public static final TesterServletContext mockServletContext =
new TesterServletContext();
+ // Default config for the test is to allow any origin
public static FilterConfig getDefaultFilterConfig() {
final String allowedHttpHeaders =
CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
final String allowedHttpMethods =
CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS;
- final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
+ final String allowedOrigins = ANY_ORIGIN;
final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
final String supportCredentials =
CorsFilter.DEFAULT_SUPPORTS_CREDENTIALS;
@@ -59,7 +60,7 @@ public static FilterConfig getFilterConfigAnyOriginAndSupportsCredentials() {
CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
final String allowedHttpMethods =
CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS + ",PUT";
- final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
+ final String allowedOrigins = ANY_ORIGIN;
final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
final String supportCredentials = "true";
final String preflightMaxAge =
@@ -77,7 +78,7 @@ public static FilterConfig getFilterConfigAnyOriginAndSupportsCredentials() {
CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
final String allowedHttpMethods =
CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS + ",PUT";
- final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
+ final String allowedOrigins = ANY_ORIGIN;
final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
final String supportCredentials = "false";
final String preflightMaxAge =
@@ -131,7 +132,7 @@ public static FilterConfig getFilterConfigWithExposedHeaders() {
CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
final String allowedHttpMethods =
CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS;
- final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
+ final String allowedOrigins = ANY_ORIGIN;
final String exposedHeaders = EXPOSED_HEADERS;
final String supportCredentials =
CorsFilter.DEFAULT_SUPPORTS_CREDENTIALS;
@@ -240,7 +241,7 @@ public static FilterConfig getFilterConfigDecorateRequestDisabled() {
CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
final String allowedHttpMethods =
CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS;
- final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
+ final String allowedOrigins = ANY_ORIGIN;
final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
final String supportCredentials =
CorsFilter.DEFAULT_SUPPORTS_CREDENTIALS;
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index e221fdcd1..f36507daf 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -89,6 +89,10 @@
60490: Various formatting and layout improvements for the
ErrorReportValve
. Patch provided by Michael Osipov. (markt)
+
+ 62343: Make CORS filter defaults more secure. This is the fix
+ for CVE-2018-8014. (markt)
+