Changeset 209261 in webkit
- Timestamp:
- Dec 2, 2016, 1:33:51 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r209259 r209261 1 2016-12-02 John Wilander <wilander@apple.com> 2 3 Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language 4 https://bugs.webkit.org/show_bug.cgi?id=165178 5 <rdar://problem/18792250> 6 7 Reviewed by Youenn Fablet. 8 9 Fetch currently only restricts the header Content-Type for simple requests: 10 https://fetch.spec.whatwg.org/#cors-safelisted-request-header 11 12 This means simple CORS requests can send unexpected characters in Accept, 13 Accept-Language, and Content-Language header values. 14 15 RFC 7231 implies restrictions on these header values: 16 - Accept https://tools.ietf.org/html/rfc7231#section-5.3.2 17 - Accept-Language https://tools.ietf.org/html/rfc7231#section-5.3.5 18 - Content-Language https://tools.ietf.org/html/rfc7231#section-3.1.3.2 19 20 As per discussions in the W3C WebAppSec group we should try to restrict 21 these header values to help protect servers that do not expect simple CORS 22 requests. 23 24 Non-standard, safelisted header values should trigger a preflight and require 25 the headers to be whitelisted in the response's Access-Control-Allow-Headers. 26 For Fetch in no-cors mode this change means non-standard header values are not 27 allowed to be set. 28 29 * http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight-expected.txt: Added. 30 * http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html: Added. 31 Tests that: 32 - Normal Accept, Accept-Language, and Content-Language headers don't trigger 33 a preflight. 34 - Abnormal Accept, Accept-Language, and Content-Language headers do trigger 35 a preflight. 36 - Abnormal Accept, Accept-Language, and Content-Language headers are 37 accepted if the server whitelists them. 38 * http/tests/xmlhttprequest/resources/cors-preflight-safelisted-headers-responder.php: Added. 39 1 40 2016-12-02 Zalan Bujtas <zalan@apple.com> 2 41 -
trunk/Source/WebCore/ChangeLog
r209259 r209261 1 2016-12-02 John Wilander <wilander@apple.com> 2 3 Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language 4 https://bugs.webkit.org/show_bug.cgi?id=165178 5 <rdar://problem/18792250> 6 7 Reviewed by Youenn Fablet. 8 9 Fetch currently only restricts the header Content-Type for simple requests: 10 https://fetch.spec.whatwg.org/#cors-safelisted-request-header 11 12 This means simple CORS requests can send unexpected characters in Accept, 13 Accept-Language, and Content-Language header values. 14 15 RFC 7231 implies restrictions on these header values: 16 - Accept https://tools.ietf.org/html/rfc7231#section-5.3.2 17 - Accept-Language https://tools.ietf.org/html/rfc7231#section-5.3.5 18 - Content-Language https://tools.ietf.org/html/rfc7231#section-3.1.3.2 19 20 As per discussions in the W3C WebAppSec group we should try to restrict 21 these header values to help protect servers that do not expect simple CORS 22 requests. 23 24 Non-standard, safelisted header values should trigger a preflight and require 25 the headers to be whitelisted in the response's Access-Control-Allow-Headers. 26 For Fetch in no-cors mode this change means non-standard header values are not 27 allowed to be set. 28 29 Test: http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html 30 31 * loader/CrossOriginAccessControl.cpp: 32 (WebCore::isSimpleCrossOriginAccessRequest): 33 Now calls WebCore::isCrossOriginSafeRequestHeader() instead of 34 WebCore::isOnAccessControlSimpleRequestHeaderWhitelist(). 35 (WebCore::isOnAccessControlSimpleRequestHeaderWhitelist): Deleted. 36 It was a duplicate of WebCore::isCrossOriginSafeRequestHeader(). 37 * loader/CrossOriginAccessControl.h: 38 * loader/CrossOriginPreflightResultCache.cpp: 39 (WebCore::CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders): 40 Now calls WebCore::isCrossOriginSafeRequestHeader() instead of 41 WebCore::isOnAccessControlSimpleRequestHeaderWhitelist(). 42 * platform/network/HTTPParsers.cpp: 43 (WebCore::isValidAcceptHeaderValue): 44 Basic check that the characters are all ASCII alphanumeric, ' ', '*', '.', 45 '/', ';', or '='. 46 (WebCore::isValidLanguageHeaderValue): 47 Basic check that the characters are all ASCII alphanumeric, ' ', '*', '-', 48 '.', ';', or '='. 49 (WebCore::isSimpleHeader): 50 Removed duplicate code. Now calls WebCore::isCrossOriginSafeRequestHeader(). 51 (WebCore::isCrossOriginSafeRequestHeader): 52 Now makes a call to WebCore::isValidAcceptHeaderValue() for Accept 53 headers and WebCore::isValidLanguageHeaderValue() for Accept-Language 54 and Content-Language headers. 55 * platform/network/HTTPParsers.h: 56 1 57 2016-12-02 Zalan Bujtas <zalan@apple.com> 2 58 -
trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp
r207769 r209261 46 46 } 47 47 48 bool isOnAccessControlSimpleRequestHeaderWhitelist(HTTPHeaderName name, const String& value)49 {50 switch (name) {51 case HTTPHeaderName::Accept:52 case HTTPHeaderName::AcceptLanguage:53 case HTTPHeaderName::ContentLanguage:54 return true;55 case HTTPHeaderName::ContentType: {56 // Preflight is required for MIME types that can not be sent via form submission.57 String mimeType = extractMIMETypeFromMediaType(value);58 return equalIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded")59 || equalIgnoringASCIICase(mimeType, "multipart/form-data")60 || equalIgnoringASCIICase(mimeType, "text/plain");61 }62 default:63 return false;64 }65 }66 67 48 bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& headerMap) 68 49 { … … 71 52 72 53 for (const auto& header : headerMap) { 73 if (!header.keyAsHTTPHeaderName || !is OnAccessControlSimpleRequestHeaderWhitelist(header.keyAsHTTPHeaderName.value(), header.value))54 if (!header.keyAsHTTPHeaderName || !isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value)) 74 55 return false; 75 56 } -
trunk/Source/WebCore/loader/CrossOriginAccessControl.h
r208646 r209261 41 41 bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&); 42 42 bool isOnAccessControlSimpleRequestMethodWhitelist(const String&); 43 bool isOnAccessControlSimpleRequestHeaderWhitelist(HTTPHeaderName, const String& value);44 43 bool isOnAccessControlResponseHeaderWhitelist(const String&); 45 44 -
trunk/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
r202198 r209261 30 30 #include "CrossOriginAccessControl.h" 31 31 #include "HTTPHeaderNames.h" 32 #include "HTTPParsers.h" 32 33 #include "ResourceResponse.h" 33 34 #include <wtf/MainThread.h> … … 128 129 { 129 130 for (const auto& header : requestHeaders) { 130 if (header.keyAsHTTPHeaderName && is OnAccessControlSimpleRequestHeaderWhitelist(header.keyAsHTTPHeaderName.value(), header.value))131 if (header.keyAsHTTPHeaderName && isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value)) 131 132 continue; 132 133 if (!m_headers.contains(header.key)) { -
trunk/Source/WebCore/platform/network/HTTPParsers.cpp
r208985 r209261 35 35 36 36 #include "HTTPHeaderNames.h" 37 #include "Language.h" 37 38 #include <wtf/DateMath.h> 38 39 #include <wtf/NeverDestroyed.h> … … 124 125 return false; 125 126 } 127 return true; 128 } 129 130 // See RFC 7231, Section 5.3.2 131 bool isValidAcceptHeaderValue(const String& value) 132 { 133 for (unsigned i = 0; i < value.length(); ++i) { 134 UChar c = value[i]; 135 if (isASCIIAlphanumeric(c) || c == ' ' || c == '*' || c == '.' || c == '/' || c == ';' || c == '=') 136 continue; 137 return false; 138 } 139 140 return true; 141 } 142 143 // See RFC 7231, Section 5.3.5 and 3.1.3.2 144 bool isValidLanguageHeaderValue(const String& value) 145 { 146 for (unsigned i = 0; i < value.length(); ++i) { 147 UChar c = value[i]; 148 if (isASCIIAlphanumeric(c) || c == ' ' || c == '*' || c == '-' || c == '.' || c == ';' || c == '=') 149 continue; 150 return false; 151 } 152 153 // FIXME: Validate further by splitting into language tags and optional quality 154 // values (q=) and then check each language tag. 155 // Language tags https://tools.ietf.org/html/rfc7231#section-3.1.3.1 156 // Language tag syntax https://tools.ietf.org/html/bcp47#section-2.1 126 157 return true; 127 158 } … … 733 764 } 734 765 735 // Impleme mtnation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name766 // Implementation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name 736 767 bool isForbiddenHeaderName(const String& name) 737 768 { … … 777 808 if (!findHTTPHeaderName(name, headerName)) 778 809 return false; 779 switch (headerName) { 780 case HTTPHeaderName::Accept: 781 case HTTPHeaderName::AcceptLanguage: 782 case HTTPHeaderName::ContentLanguage: 783 return true; 784 case HTTPHeaderName::ContentType: { 785 String mimeType = extractMIMETypeFromMediaType(value); 786 return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain"); 787 } 788 default: 789 return false; 790 } 810 return isCrossOriginSafeRequestHeader(headerName, value); 791 811 } 792 812 … … 825 845 switch (name) { 826 846 case HTTPHeaderName::Accept: 847 return isValidAcceptHeaderValue(value); 827 848 case HTTPHeaderName::AcceptLanguage: 828 849 case HTTPHeaderName::ContentLanguage: 829 return true;850 return isValidLanguageHeaderValue(value); 830 851 case HTTPHeaderName::ContentType: { 852 // Preflight is required for MIME types that can not be sent via form submission. 831 853 String mimeType = extractMIMETypeFromMediaType(value); 832 854 return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain"); -
trunk/Source/WebCore/platform/network/HTTPParsers.h
r208985 r209261 70 70 bool isValidReasonPhrase(const String&); 71 71 bool isValidHTTPHeaderValue(const String&); 72 bool isValidAcceptHeaderValue(const String&); 73 bool isValidLanguageHeaderValue(const String&); 72 74 bool isValidHTTPToken(const String&); 73 75 bool parseHTTPRefresh(const String& refresh, double& delay, String& url);
Note:
See TracChangeset
for help on using the changeset viewer.