| Index: third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
|
| diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
|
| deleted file mode 100644
|
| index e429ce978f078e86ac6b5b18795deca5988e7892..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
|
| +++ /dev/null
|
| @@ -1,565 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "core/frame/csp/CSPSourceList.h"
|
| -
|
| -#include "core/frame/csp/CSPSource.h"
|
| -#include "core/frame/csp/ContentSecurityPolicy.h"
|
| -#include "platform/weborigin/KURL.h"
|
| -#include "platform/weborigin/SecurityOrigin.h"
|
| -#include "wtf/HashSet.h"
|
| -#include "wtf/text/Base64.h"
|
| -#include "wtf/text/ParsingUtilities.h"
|
| -#include "wtf/text/StringToNumber.h"
|
| -#include "wtf/text/WTFString.h"
|
| -
|
| -namespace blink {
|
| -
|
| -static bool isSourceListNone(const UChar* begin, const UChar* end) {
|
| - skipWhile<UChar, isASCIISpace>(begin, end);
|
| -
|
| - const UChar* position = begin;
|
| - skipWhile<UChar, isSourceCharacter>(position, end);
|
| - if (!equalIgnoringCase("'none'", StringView(begin, position - begin)))
|
| - return false;
|
| -
|
| - skipWhile<UChar, isASCIISpace>(position, end);
|
| - if (position != end)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy,
|
| - const String& directiveName)
|
| - : m_policy(policy),
|
| - m_directiveName(directiveName),
|
| - m_allowSelf(false),
|
| - m_allowStar(false),
|
| - m_allowInline(false),
|
| - m_allowEval(false),
|
| - m_allowDynamic(false),
|
| - m_allowHashedAttributes(false),
|
| - m_hashAlgorithmsUsed(0) {}
|
| -
|
| -bool CSPSourceList::matches(
|
| - const KURL& url,
|
| - ResourceRequest::RedirectStatus redirectStatus) const {
|
| - // Wildcards match network schemes ('http', 'https', 'ftp', 'ws', 'wss'), and
|
| - // the scheme of the protected resource:
|
| - // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
|
| - // schemes, including custom schemes, must be explicitly listed in a source
|
| - // list.
|
| - if (m_allowStar) {
|
| - if (url.protocolIsInHTTPFamily() || url.protocolIs("ftp") ||
|
| - url.protocolIs("ws") || url.protocolIs("wss") ||
|
| - m_policy->protocolMatchesSelf(url))
|
| - return true;
|
| -
|
| - return hasSourceMatchInList(url, redirectStatus);
|
| - }
|
| -
|
| - KURL effectiveURL =
|
| - m_policy->selfMatchesInnerURL() && SecurityOrigin::shouldUseInnerURL(url)
|
| - ? SecurityOrigin::extractInnerURL(url)
|
| - : url;
|
| -
|
| - if (m_allowSelf && m_policy->urlMatchesSelf(effectiveURL))
|
| - return true;
|
| -
|
| - return hasSourceMatchInList(effectiveURL, redirectStatus);
|
| -}
|
| -
|
| -bool CSPSourceList::allowInline() const {
|
| - return m_allowInline;
|
| -}
|
| -
|
| -bool CSPSourceList::allowEval() const {
|
| - return m_allowEval;
|
| -}
|
| -
|
| -bool CSPSourceList::allowDynamic() const {
|
| - return m_allowDynamic;
|
| -}
|
| -
|
| -bool CSPSourceList::allowNonce(const String& nonce) const {
|
| - return !nonce.isNull() && m_nonces.contains(nonce);
|
| -}
|
| -
|
| -bool CSPSourceList::allowHash(const CSPHashValue& hashValue) const {
|
| - return m_hashes.contains(hashValue);
|
| -}
|
| -
|
| -bool CSPSourceList::allowHashedAttributes() const {
|
| - return m_allowHashedAttributes;
|
| -}
|
| -
|
| -uint8_t CSPSourceList::hashAlgorithmsUsed() const {
|
| - return m_hashAlgorithmsUsed;
|
| -}
|
| -
|
| -bool CSPSourceList::isHashOrNoncePresent() const {
|
| - return !m_nonces.isEmpty() ||
|
| - m_hashAlgorithmsUsed != ContentSecurityPolicyHashAlgorithmNone;
|
| -}
|
| -
|
| -// source-list = *WSP [ source *( 1*WSP source ) *WSP ]
|
| -// / *WSP "'none'" *WSP
|
| -//
|
| -void CSPSourceList::parse(const UChar* begin, const UChar* end) {
|
| - // We represent 'none' as an empty m_list.
|
| - if (isSourceListNone(begin, end))
|
| - return;
|
| -
|
| - const UChar* position = begin;
|
| - while (position < end) {
|
| - skipWhile<UChar, isASCIISpace>(position, end);
|
| - if (position == end)
|
| - return;
|
| -
|
| - const UChar* beginSource = position;
|
| - skipWhile<UChar, isSourceCharacter>(position, end);
|
| -
|
| - String scheme, host, path;
|
| - int port = 0;
|
| - CSPSource::WildcardDisposition hostWildcard = CSPSource::NoWildcard;
|
| - CSPSource::WildcardDisposition portWildcard = CSPSource::NoWildcard;
|
| -
|
| - if (parseSource(beginSource, position, scheme, host, port, path,
|
| - hostWildcard, portWildcard)) {
|
| - // Wildcard hosts and keyword sources ('self', 'unsafe-inline',
|
| - // etc.) aren't stored in m_list, but as attributes on the source
|
| - // list itself.
|
| - if (scheme.isEmpty() && host.isEmpty())
|
| - continue;
|
| - if (m_policy->isDirectiveName(host))
|
| - m_policy->reportDirectiveAsSourceExpression(m_directiveName, host);
|
| - m_list.append(new CSPSource(m_policy, scheme, host, port, path,
|
| - hostWildcard, portWildcard));
|
| - } else {
|
| - m_policy->reportInvalidSourceExpression(
|
| - m_directiveName, String(beginSource, position - beginSource));
|
| - }
|
| -
|
| - ASSERT(position == end || isASCIISpace(*position));
|
| - }
|
| -}
|
| -
|
| -// source = scheme ":"
|
| -// / ( [ scheme "://" ] host [ port ] [ path ] )
|
| -// / "'self'"
|
| -bool CSPSourceList::parseSource(const UChar* begin,
|
| - const UChar* end,
|
| - String& scheme,
|
| - String& host,
|
| - int& port,
|
| - String& path,
|
| - CSPSource::WildcardDisposition& hostWildcard,
|
| - CSPSource::WildcardDisposition& portWildcard) {
|
| - if (begin == end)
|
| - return false;
|
| -
|
| - StringView token(begin, end - begin);
|
| -
|
| - if (equalIgnoringCase("'none'", token))
|
| - return false;
|
| -
|
| - if (end - begin == 1 && *begin == '*') {
|
| - addSourceStar();
|
| - return true;
|
| - }
|
| -
|
| - if (equalIgnoringCase("'self'", token)) {
|
| - addSourceSelf();
|
| - return true;
|
| - }
|
| -
|
| - if (equalIgnoringCase("'unsafe-inline'", token)) {
|
| - addSourceUnsafeInline();
|
| - return true;
|
| - }
|
| -
|
| - if (equalIgnoringCase("'unsafe-eval'", token)) {
|
| - addSourceUnsafeEval();
|
| - return true;
|
| - }
|
| -
|
| - if (equalIgnoringCase("'strict-dynamic'", token)) {
|
| - addSourceStrictDynamic();
|
| - return true;
|
| - }
|
| -
|
| - if (equalIgnoringCase("'unsafe-hashed-attributes'", token)) {
|
| - addSourceUnsafeHashedAttributes();
|
| - return true;
|
| - }
|
| -
|
| - String nonce;
|
| - if (!parseNonce(begin, end, nonce))
|
| - return false;
|
| -
|
| - if (!nonce.isNull()) {
|
| - addSourceNonce(nonce);
|
| - return true;
|
| - }
|
| -
|
| - DigestValue hash;
|
| - ContentSecurityPolicyHashAlgorithm algorithm =
|
| - ContentSecurityPolicyHashAlgorithmNone;
|
| - if (!parseHash(begin, end, hash, algorithm))
|
| - return false;
|
| -
|
| - if (hash.size() > 0) {
|
| - addSourceHash(algorithm, hash);
|
| - return true;
|
| - }
|
| -
|
| - const UChar* position = begin;
|
| - const UChar* beginHost = begin;
|
| - const UChar* beginPath = end;
|
| - const UChar* beginPort = 0;
|
| -
|
| - skipWhile<UChar, isNotColonOrSlash>(position, end);
|
| -
|
| - if (position == end) {
|
| - // host
|
| - // ^
|
| - return parseHost(beginHost, position, host, hostWildcard);
|
| - }
|
| -
|
| - if (position < end && *position == '/') {
|
| - // host/path || host/ || /
|
| - // ^ ^ ^
|
| - return parseHost(beginHost, position, host, hostWildcard) &&
|
| - parsePath(position, end, path);
|
| - }
|
| -
|
| - if (position < end && *position == ':') {
|
| - if (end - position == 1) {
|
| - // scheme:
|
| - // ^
|
| - return parseScheme(begin, position, scheme);
|
| - }
|
| -
|
| - if (position[1] == '/') {
|
| - // scheme://host || scheme://
|
| - // ^ ^
|
| - if (!parseScheme(begin, position, scheme) ||
|
| - !skipExactly<UChar>(position, end, ':') ||
|
| - !skipExactly<UChar>(position, end, '/') ||
|
| - !skipExactly<UChar>(position, end, '/'))
|
| - return false;
|
| - if (position == end)
|
| - return false;
|
| - beginHost = position;
|
| - skipWhile<UChar, isNotColonOrSlash>(position, end);
|
| - }
|
| -
|
| - if (position < end && *position == ':') {
|
| - // host:port || scheme://host:port
|
| - // ^ ^
|
| - beginPort = position;
|
| - skipUntil<UChar>(position, end, '/');
|
| - }
|
| - }
|
| -
|
| - if (position < end && *position == '/') {
|
| - // scheme://host/path || scheme://host:port/path
|
| - // ^ ^
|
| - if (position == beginHost)
|
| - return false;
|
| - beginPath = position;
|
| - }
|
| -
|
| - if (!parseHost(beginHost, beginPort ? beginPort : beginPath, host,
|
| - hostWildcard))
|
| - return false;
|
| -
|
| - if (beginPort) {
|
| - if (!parsePort(beginPort, beginPath, port, portWildcard))
|
| - return false;
|
| - } else {
|
| - port = 0;
|
| - }
|
| -
|
| - if (beginPath != end) {
|
| - if (!parsePath(beginPath, end, path))
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// nonce-source = "'nonce-" nonce-value "'"
|
| -// nonce-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
|
| -//
|
| -bool CSPSourceList::parseNonce(const UChar* begin,
|
| - const UChar* end,
|
| - String& nonce) {
|
| - size_t nonceLength = end - begin;
|
| - StringView prefix("'nonce-");
|
| -
|
| - // TODO(esprehn): Should be StringView(begin, nonceLength).startsWith(prefix).
|
| - if (nonceLength <= prefix.length() ||
|
| - !equalIgnoringCase(prefix, StringView(begin, prefix.length())))
|
| - return true;
|
| -
|
| - const UChar* position = begin + prefix.length();
|
| - const UChar* nonceBegin = position;
|
| -
|
| - ASSERT(position < end);
|
| - skipWhile<UChar, isNonceCharacter>(position, end);
|
| - ASSERT(nonceBegin <= position);
|
| -
|
| - if (position + 1 != end || *position != '\'' || position == nonceBegin)
|
| - return false;
|
| -
|
| - nonce = String(nonceBegin, position - nonceBegin);
|
| - return true;
|
| -}
|
| -
|
| -// hash-source = "'" hash-algorithm "-" hash-value "'"
|
| -// hash-algorithm = "sha1" / "sha256" / "sha384" / "sha512"
|
| -// hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
|
| -//
|
| -bool CSPSourceList::parseHash(
|
| - const UChar* begin,
|
| - const UChar* end,
|
| - DigestValue& hash,
|
| - ContentSecurityPolicyHashAlgorithm& hashAlgorithm) {
|
| - // Any additions or subtractions from this struct should also modify the
|
| - // respective entries in the kAlgorithmMap array in checkDigest().
|
| - static const struct {
|
| - const char* prefix;
|
| - ContentSecurityPolicyHashAlgorithm type;
|
| - } kSupportedPrefixes[] = {
|
| - // FIXME: Drop support for SHA-1. It's not in the spec.
|
| - {"'sha1-", ContentSecurityPolicyHashAlgorithmSha1},
|
| - {"'sha256-", ContentSecurityPolicyHashAlgorithmSha256},
|
| - {"'sha384-", ContentSecurityPolicyHashAlgorithmSha384},
|
| - {"'sha512-", ContentSecurityPolicyHashAlgorithmSha512},
|
| - {"'sha-256-", ContentSecurityPolicyHashAlgorithmSha256},
|
| - {"'sha-384-", ContentSecurityPolicyHashAlgorithmSha384},
|
| - {"'sha-512-", ContentSecurityPolicyHashAlgorithmSha512}};
|
| -
|
| - StringView prefix;
|
| - hashAlgorithm = ContentSecurityPolicyHashAlgorithmNone;
|
| - size_t hashLength = end - begin;
|
| -
|
| - for (const auto& algorithm : kSupportedPrefixes) {
|
| - prefix = algorithm.prefix;
|
| - // TODO(esprehn): Should be StringView(begin, end -
|
| - // begin).startsWith(prefix).
|
| - if (hashLength > prefix.length() &&
|
| - equalIgnoringCase(prefix, StringView(begin, prefix.length()))) {
|
| - hashAlgorithm = algorithm.type;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (hashAlgorithm == ContentSecurityPolicyHashAlgorithmNone)
|
| - return true;
|
| -
|
| - const UChar* position = begin + prefix.length();
|
| - const UChar* hashBegin = position;
|
| -
|
| - ASSERT(position < end);
|
| - skipWhile<UChar, isBase64EncodedCharacter>(position, end);
|
| - ASSERT(hashBegin <= position);
|
| -
|
| - // Base64 encodings may end with exactly one or two '=' characters
|
| - if (position < end)
|
| - skipExactly<UChar>(position, position + 1, '=');
|
| - if (position < end)
|
| - skipExactly<UChar>(position, position + 1, '=');
|
| -
|
| - if (position + 1 != end || *position != '\'' || position == hashBegin)
|
| - return false;
|
| -
|
| - Vector<char> hashVector;
|
| - // We accept base64url-encoded data here by normalizing it to base64.
|
| - base64Decode(normalizeToBase64(String(hashBegin, position - hashBegin)),
|
| - hashVector);
|
| - if (hashVector.size() > kMaxDigestSize)
|
| - return false;
|
| - hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size());
|
| - return true;
|
| -}
|
| -
|
| -// ; <scheme> production from RFC 3986
|
| -// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
| -//
|
| -bool CSPSourceList::parseScheme(const UChar* begin,
|
| - const UChar* end,
|
| - String& scheme) {
|
| - ASSERT(begin <= end);
|
| - ASSERT(scheme.isEmpty());
|
| -
|
| - if (begin == end)
|
| - return false;
|
| -
|
| - const UChar* position = begin;
|
| -
|
| - if (!skipExactly<UChar, isASCIIAlpha>(position, end))
|
| - return false;
|
| -
|
| - skipWhile<UChar, isSchemeContinuationCharacter>(position, end);
|
| -
|
| - if (position != end)
|
| - return false;
|
| -
|
| - scheme = String(begin, end - begin);
|
| - return true;
|
| -}
|
| -
|
| -// host = [ "*." ] 1*host-char *( "." 1*host-char )
|
| -// / "*"
|
| -// host-char = ALPHA / DIGIT / "-"
|
| -//
|
| -bool CSPSourceList::parseHost(const UChar* begin,
|
| - const UChar* end,
|
| - String& host,
|
| - CSPSource::WildcardDisposition& hostWildcard) {
|
| - ASSERT(begin <= end);
|
| - ASSERT(host.isEmpty());
|
| - ASSERT(hostWildcard == CSPSource::NoWildcard);
|
| -
|
| - if (begin == end)
|
| - return false;
|
| -
|
| - const UChar* position = begin;
|
| -
|
| - if (skipExactly<UChar>(position, end, '*')) {
|
| - hostWildcard = CSPSource::HasWildcard;
|
| -
|
| - if (position == end)
|
| - return true;
|
| -
|
| - if (!skipExactly<UChar>(position, end, '.'))
|
| - return false;
|
| - }
|
| -
|
| - const UChar* hostBegin = position;
|
| -
|
| - while (position < end) {
|
| - if (!skipExactly<UChar, isHostCharacter>(position, end))
|
| - return false;
|
| -
|
| - skipWhile<UChar, isHostCharacter>(position, end);
|
| -
|
| - if (position < end && !skipExactly<UChar>(position, end, '.'))
|
| - return false;
|
| - }
|
| -
|
| - ASSERT(position == end);
|
| - host = String(hostBegin, end - hostBegin);
|
| - return true;
|
| -}
|
| -
|
| -bool CSPSourceList::parsePath(const UChar* begin,
|
| - const UChar* end,
|
| - String& path) {
|
| - ASSERT(begin <= end);
|
| - ASSERT(path.isEmpty());
|
| -
|
| - const UChar* position = begin;
|
| - skipWhile<UChar, isPathComponentCharacter>(position, end);
|
| - // path/to/file.js?query=string || path/to/file.js#anchor
|
| - // ^ ^
|
| - if (position < end)
|
| - m_policy->reportInvalidPathCharacter(m_directiveName,
|
| - String(begin, end - begin), *position);
|
| -
|
| - path = decodeURLEscapeSequences(String(begin, position - begin));
|
| -
|
| - ASSERT(position <= end);
|
| - ASSERT(position == end || (*position == '#' || *position == '?'));
|
| - return true;
|
| -}
|
| -
|
| -// port = ":" ( 1*DIGIT / "*" )
|
| -//
|
| -bool CSPSourceList::parsePort(const UChar* begin,
|
| - const UChar* end,
|
| - int& port,
|
| - CSPSource::WildcardDisposition& portWildcard) {
|
| - ASSERT(begin <= end);
|
| - ASSERT(!port);
|
| - ASSERT(portWildcard == CSPSource::NoWildcard);
|
| -
|
| - if (!skipExactly<UChar>(begin, end, ':'))
|
| - ASSERT_NOT_REACHED();
|
| -
|
| - if (begin == end)
|
| - return false;
|
| -
|
| - if (end - begin == 1 && *begin == '*') {
|
| - port = 0;
|
| - portWildcard = CSPSource::HasWildcard;
|
| - return true;
|
| - }
|
| -
|
| - const UChar* position = begin;
|
| - skipWhile<UChar, isASCIIDigit>(position, end);
|
| -
|
| - if (position != end)
|
| - return false;
|
| -
|
| - bool ok;
|
| - port = charactersToIntStrict(begin, end - begin, &ok);
|
| - return ok;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceSelf() {
|
| - m_allowSelf = true;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceStar() {
|
| - m_allowStar = true;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceUnsafeInline() {
|
| - m_allowInline = true;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceUnsafeEval() {
|
| - m_allowEval = true;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceStrictDynamic() {
|
| - m_allowDynamic = true;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceUnsafeHashedAttributes() {
|
| - m_allowHashedAttributes = true;
|
| -}
|
| -
|
| -void CSPSourceList::addSourceNonce(const String& nonce) {
|
| - m_nonces.add(nonce);
|
| -}
|
| -
|
| -void CSPSourceList::addSourceHash(
|
| - const ContentSecurityPolicyHashAlgorithm& algorithm,
|
| - const DigestValue& hash) {
|
| - m_hashes.add(CSPHashValue(algorithm, hash));
|
| - m_hashAlgorithmsUsed |= algorithm;
|
| -}
|
| -
|
| -bool CSPSourceList::hasSourceMatchInList(
|
| - const KURL& url,
|
| - ResourceRequest::RedirectStatus redirectStatus) const {
|
| - for (size_t i = 0; i < m_list.size(); ++i) {
|
| - if (m_list[i]->matches(url, redirectStatus))
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -DEFINE_TRACE(CSPSourceList) {
|
| - visitor->trace(m_policy);
|
| - visitor->trace(m_list);
|
| -}
|
| -
|
| -} // namespace blink
|
|
|