这是indexloc提供的服务,不要输入任何密码

Changeset 209261 in webkit


Ignore:
Timestamp:
Dec 2, 2016, 1:33:51 PM (9 years ago)
Author:
wilander@apple.com
Message:

Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language
https://bugs.webkit.org/show_bug.cgi?id=165178
<rdar://problem/18792250>

Reviewed by Youenn Fablet.

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:

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.

Source/WebCore:

Test: http/tests/xmlhttprequest/cors-non-standard-safelisted-headers-should-trigger-preflight.html

  • loader/CrossOriginAccessControl.cpp:

(WebCore::isSimpleCrossOriginAccessRequest):

Now calls WebCore::isCrossOriginSafeRequestHeader() instead of
WebCore::isOnAccessControlSimpleRequestHeaderWhitelist().

(WebCore::isOnAccessControlSimpleRequestHeaderWhitelist): Deleted.

It was a duplicate of WebCore::isCrossOriginSafeRequestHeader().

  • loader/CrossOriginAccessControl.h:
  • loader/CrossOriginPreflightResultCache.cpp:

(WebCore::CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders):

Now calls WebCore::isCrossOriginSafeRequestHeader() instead of
WebCore::isOnAccessControlSimpleRequestHeaderWhitelist().

  • 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):

Removed duplicate code. Now calls WebCore::isCrossOriginSafeRequestHeader().

(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:

LayoutTests:

  • 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.
Location:
trunk
Files:
3 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r209259 r209261  
     12016-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
    1402016-12-02  Zalan Bujtas  <zalan@apple.com>
    241
  • trunk/Source/WebCore/ChangeLog

    r209259 r209261  
     12016-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
    1572016-12-02  Zalan Bujtas  <zalan@apple.com>
    258
  • trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp

    r207769 r209261  
    4646}
    4747
    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 
    6748bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& headerMap)
    6849{
     
    7152
    7253    for (const auto& header : headerMap) {
    73         if (!header.keyAsHTTPHeaderName || !isOnAccessControlSimpleRequestHeaderWhitelist(header.keyAsHTTPHeaderName.value(), header.value))
     54        if (!header.keyAsHTTPHeaderName || !isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value))
    7455            return false;
    7556    }
  • trunk/Source/WebCore/loader/CrossOriginAccessControl.h

    r208646 r209261  
    4141bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&);
    4242bool isOnAccessControlSimpleRequestMethodWhitelist(const String&);
    43 bool isOnAccessControlSimpleRequestHeaderWhitelist(HTTPHeaderName, const String& value);
    4443bool isOnAccessControlResponseHeaderWhitelist(const String&);
    4544
  • trunk/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp

    r202198 r209261  
    3030#include "CrossOriginAccessControl.h"
    3131#include "HTTPHeaderNames.h"
     32#include "HTTPParsers.h"
    3233#include "ResourceResponse.h"
    3334#include <wtf/MainThread.h>
     
    128129{
    129130    for (const auto& header : requestHeaders) {
    130         if (header.keyAsHTTPHeaderName && isOnAccessControlSimpleRequestHeaderWhitelist(header.keyAsHTTPHeaderName.value(), header.value))
     131        if (header.keyAsHTTPHeaderName && isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value))
    131132            continue;
    132133        if (!m_headers.contains(header.key)) {
  • trunk/Source/WebCore/platform/network/HTTPParsers.cpp

    r208985 r209261  
    3535
    3636#include "HTTPHeaderNames.h"
     37#include "Language.h"
    3738#include <wtf/DateMath.h>
    3839#include <wtf/NeverDestroyed.h>
     
    124125            return false;
    125126    }
     127    return true;
     128}
     129
     130// See RFC 7231, Section 5.3.2
     131bool 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
     144bool 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
    126157    return true;
    127158}
     
    733764}
    734765
    735 // Implememtnation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
     766// Implementation of https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
    736767bool isForbiddenHeaderName(const String& name)
    737768{
     
    777808    if (!findHTTPHeaderName(name, headerName))
    778809        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);
    791811}
    792812
     
    825845    switch (name) {
    826846    case HTTPHeaderName::Accept:
     847        return isValidAcceptHeaderValue(value);
    827848    case HTTPHeaderName::AcceptLanguage:
    828849    case HTTPHeaderName::ContentLanguage:
    829         return true;
     850        return isValidLanguageHeaderValue(value);
    830851    case HTTPHeaderName::ContentType: {
     852        // Preflight is required for MIME types that can not be sent via form submission.
    831853        String mimeType = extractMIMETypeFromMediaType(value);
    832854        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  
    7070bool isValidReasonPhrase(const String&);
    7171bool isValidHTTPHeaderValue(const String&);
     72bool isValidAcceptHeaderValue(const String&);
     73bool isValidLanguageHeaderValue(const String&);
    7274bool isValidHTTPToken(const String&);
    7375bool parseHTTPRefresh(const String& refresh, double& delay, String& url);
Note: See TracChangeset for help on using the changeset viewer.