Index: Source/WebCore/ChangeLog =================================================================== --- Source/WebCore/ChangeLog (revision 209184) +++ Source/WebCore/ChangeLog (working copy) @@ -1,3 +1,55 @@ +2016-12-01 John Wilander + + Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language + https://bugs.webkit.org/show_bug.cgi?id=165178 + + + Reviewed by NOBODY (OOPS!). + + Fetch currently only restricts the header Content-Type for simple requests: + https://fetch.spec.whatwg.org/#cors-safelisted-request-header + + This means simple CORS requests can send unexpected characters in Accept, + Accept-Language, and Content-Language header values. + + RFC 7231 implies restrictions on these header values: + - Accept https://tools.ietf.org/html/rfc7231#section-5.3.2 + - Accept-Language https://tools.ietf.org/html/rfc7231#section-5.3.5 + - Content-Language https://tools.ietf.org/html/rfc7231#section-3.1.3.2 + + As per discussions in the W3C WebAppSec group we should try to restrict + these header values to help protect servers that do not expect simple CORS + requests. + + Non-standard, safelisted header values should trigger a preflight and require + the headers to be whitelisted in the response's Access-Control-Allow-Headers. + For Fetch in no-cors mode this change means non-standard header values are not + allowed to be set. + + Test: http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html + + * loader/CrossOriginAccessControl.cpp: + (WebCore::isOnAccessControlSimpleRequestHeaderWhitelist): + Now makes a call to WebCore::isValidAcceptHeaderValue() for Accept + headers and WebCore::isValidLanguageHeaderValue() for Accept-Language + and Content-Language headers. + * platform/network/HTTPParsers.cpp: + (WebCore::isValidAcceptHeaderValue): + Basic check that the characters are all ASCII alphanumeric, ' ', '*', '.', + '/', ';', or '='. + (WebCore::isValidLanguageHeaderValue): + Basic check that the characters are all ASCII alphanumeric, ' ', '*', '-', + '.', ';', or '='. + (WebCore::isSimpleHeader): + Now makes a call to WebCore::isValidAcceptHeaderValue() for Accept + headers and WebCore::isValidLanguageHeaderValue() for Accept-Language + and Content-Language headers. + (WebCore::isCrossOriginSafeRequestHeader): + Now makes a call to WebCore::isValidAcceptHeaderValue() for Accept + headers and WebCore::isValidLanguageHeaderValue() for Accept-Language + and Content-Language headers. + * platform/network/HTTPParsers.h: + 2016-11-30 Sam Weinig [WebIDL] Remove custom bindings for File and Blob constructors Index: Source/WebCore/loader/CrossOriginAccessControl.cpp =================================================================== --- Source/WebCore/loader/CrossOriginAccessControl.cpp (revision 209182) +++ Source/WebCore/loader/CrossOriginAccessControl.cpp (working copy) @@ -49,9 +49,10 @@ bool isOnAccessControlSimpleRequestHeade { switch (name) { case HTTPHeaderName::Accept: + return isValidAcceptHeaderValue(value); case HTTPHeaderName::AcceptLanguage: case HTTPHeaderName::ContentLanguage: - return true; + return isValidLanguageHeaderValue(value); case HTTPHeaderName::ContentType: { // Preflight is required for MIME types that can not be sent via form submission. String mimeType = extractMIMETypeFromMediaType(value); Index: Source/WebCore/platform/network/HTTPParsers.cpp =================================================================== --- Source/WebCore/platform/network/HTTPParsers.cpp (revision 209182) +++ Source/WebCore/platform/network/HTTPParsers.cpp (working copy) @@ -34,6 +34,7 @@ #include "HTTPParsers.h" #include "HTTPHeaderNames.h" +#include "Language.h" #include #include #include @@ -126,6 +127,36 @@ bool isValidHTTPHeaderValue(const String return true; } +// See RFC 7231, Section 5.3.2 +bool isValidAcceptHeaderValue(const String& value) +{ + for (unsigned i = 0; i < value.length(); ++i) { + UChar c = value[i]; + if (isASCIIAlphanumeric(c) || c == ' ' || c == '*' || c == '.' || c == '/' || c == ';' || c == '=') + continue; + return false; + } + + return true; +} + +// See RFC 7231, Section 5.3.5 and 3.1.3.2 +bool isValidLanguageHeaderValue(const String& value) +{ + for (unsigned i = 0; i < value.length(); ++i) { + UChar c = value[i]; + if (isASCIIAlphanumeric(c) || c == ' ' || c == '*' || c == '-' || c == '.' || c == ';' || c == '=') + continue; + return false; + } + + // FIXME: Validate further by splitting into language tags and optional quality + // values (q=) and then check each language tag. + // Language tags https://tools.ietf.org/html/rfc7231#section-3.1.3.1 + // Language tag syntax https://tools.ietf.org/html/bcp47#section-2.1 + return true; +} + // See RFC 7230, Section 3.2.6. bool isValidHTTPToken(const String& value) { @@ -732,7 +763,7 @@ void parseAccessControlExposeHeadersAllo } } -// Implememtnation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name +// Implementation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name bool isForbiddenHeaderName(const String& name) { HTTPHeaderName headerName; @@ -778,9 +809,10 @@ bool isSimpleHeader(const String& name, return false; switch (headerName) { case HTTPHeaderName::Accept: + return isValidAcceptHeaderValue(value); case HTTPHeaderName::AcceptLanguage: case HTTPHeaderName::ContentLanguage: - return true; + return isValidLanguageHeaderValue(value); case HTTPHeaderName::ContentType: { String mimeType = extractMIMETypeFromMediaType(value); return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain"); @@ -824,9 +856,10 @@ bool isCrossOriginSafeRequestHeader(HTTP { switch (name) { case HTTPHeaderName::Accept: + return isValidAcceptHeaderValue(value); case HTTPHeaderName::AcceptLanguage: case HTTPHeaderName::ContentLanguage: - return true; + return isValidLanguageHeaderValue(value); case HTTPHeaderName::ContentType: { String mimeType = extractMIMETypeFromMediaType(value); return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain"); Index: Source/WebCore/platform/network/HTTPParsers.h =================================================================== --- Source/WebCore/platform/network/HTTPParsers.h (revision 209182) +++ Source/WebCore/platform/network/HTTPParsers.h (working copy) @@ -69,6 +69,8 @@ enum XFrameOptionsDisposition { bool isValidReasonPhrase(const String&); bool isValidHTTPHeaderValue(const String&); +bool isValidAcceptHeaderValue(const String&); +bool isValidLanguageHeaderValue(const String&); bool isValidHTTPToken(const String&); bool parseHTTPRefresh(const String& refresh, double& delay, String& url); std::optional parseHTTPDate(const String&); Index: LayoutTests/ChangeLog =================================================================== --- LayoutTests/ChangeLog (revision 209182) +++ LayoutTests/ChangeLog (working copy) @@ -1,3 +1,42 @@ +2016-12-01 John Wilander + + Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language + https://bugs.webkit.org/show_bug.cgi?id=165178 + + + Reviewed by NOBODY (OOPS!). + + Fetch currently only restricts the header Content-Type for simple requests: + https://fetch.spec.whatwg.org/#cors-safelisted-request-header + + This means simple CORS requests can send unexpected characters in Accept, + Accept-Language, and Content-Language header values. + + RFC 7231 implies restrictions on these header values: + - Accept https://tools.ietf.org/html/rfc7231#section-5.3.2 + - Accept-Language https://tools.ietf.org/html/rfc7231#section-5.3.5 + - Content-Language https://tools.ietf.org/html/rfc7231#section-3.1.3.2 + + As per discussions in the W3C WebAppSec group we should try to restrict + these header values to help protect servers that do not expect simple CORS + requests. + + Non-standard, safelisted header values should trigger a preflight and require + the headers to be whitelisted in the response's Access-Control-Allow-Headers. + For Fetch in no-cors mode this change means non-standard header values are not + allowed to be set. + + * http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight-expected.txt: Added. + * http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html: Added. + Tests that: + - Normal Accept, Accept-Language, and Content-Language headers don't trigger + a preflight. + - Abnormal Accept, Accept-Language, and Content-Language headers do trigger + a preflight. + - Abnormal Accept, Accept-Language, and Content-Language headers are + accepted if the server whitelists them. + * http/tests/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php: Added. + 2016-12-01 Antoine Quint [Modern Media Controls] Provide a UI object to show a list of tracks Index: LayoutTests/http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight-expected.txt =================================================================== --- LayoutTests/http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight-expected.txt (nonexistent) +++ LayoutTests/http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight-expected.txt (working copy) @@ -0,0 +1,18 @@ +CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php. Request header field Accept is not allowed by Access-Control-Allow-Headers. +CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php. Request header field Accept-Language is not allowed by Access-Control-Allow-Headers. +CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php. Request header field Content-Language is not allowed by Access-Control-Allow-Headers. +CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php. Request header field Content-Language is not allowed by Access-Control-Allow-Headers. +CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php. Request header field Accept is not allowed by Access-Control-Allow-Headers. +PASS Accept header with normal value SHOULD NOT cause a preflight +PASS Accept-Language header with normal value SHOULD NOT cause a preflight +PASS Content-Language header with normal value SHOULD NOT cause a preflight +PASS Accept header with abnormal value SHOULD cause a preflight +PASS Accept-Language header with abnormal value SHOULD cause a preflight +PASS Content-Language header with abnormal value SHOULD cause a preflight +PASS Accept header with normal value, Accept-Language header with normal value, and Content-Language header with abnormal value SHOULD cause a preflight +PASS Accept header with normal value and then another Accept header with abnormal value SHOULD cause a preflight +PASS Accept header with abnormal value and explicitly allowed headers SHOULD be allowed +PASS Content-Language header with abnormal value and explicitly allowed headers SHOULD be allowed +PASS Accept header with normal value, Accept-Language header with normal value, Content-Language header with abnormal value, and explicitly allowed headers SHOULD be allowed +PASS Accept header with normal value, then another Accept header with abnormal value, and explicitly allowed headers SHOULD be allowed + Index: LayoutTests/http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html =================================================================== --- LayoutTests/http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html (nonexistent) +++ LayoutTests/http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html (working copy) @@ -0,0 +1,147 @@ + + + + + Non-Standard Safelisted Headers SHOULD Trigger a Preflight + + + + + + + \ No newline at end of file Index: LayoutTests/http/tests/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php =================================================================== --- LayoutTests/http/tests/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php (nonexistent) +++ LayoutTests/http/tests/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php (working copy) @@ -0,0 +1,8 @@ + \ No newline at end of file