Home | History | Annotate | Download | only in csp
      1 /*
      2  * Copyright (C) 2011 Google, Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "core/frame/csp/ContentSecurityPolicy.h"
     28 
     29 #include "bindings/core/v8/ScriptCallStackFactory.h"
     30 #include "bindings/core/v8/ScriptController.h"
     31 #include "core/dom/DOMStringList.h"
     32 #include "core/dom/Document.h"
     33 #include "core/events/SecurityPolicyViolationEvent.h"
     34 #include "core/frame/LocalDOMWindow.h"
     35 #include "core/frame/LocalFrame.h"
     36 #include "core/frame/UseCounter.h"
     37 #include "core/frame/csp/CSPDirectiveList.h"
     38 #include "core/frame/csp/CSPSource.h"
     39 #include "core/frame/csp/CSPSourceList.h"
     40 #include "core/frame/csp/MediaListDirective.h"
     41 #include "core/frame/csp/SourceListDirective.h"
     42 #include "core/inspector/ConsoleMessage.h"
     43 #include "core/inspector/InspectorInstrumentation.h"
     44 #include "core/inspector/ScriptCallStack.h"
     45 #include "core/loader/DocumentLoader.h"
     46 #include "core/loader/PingLoader.h"
     47 #include "platform/Crypto.h"
     48 #include "platform/JSONValues.h"
     49 #include "platform/NotImplemented.h"
     50 #include "platform/ParsingUtilities.h"
     51 #include "platform/RuntimeEnabledFeatures.h"
     52 #include "platform/network/ContentSecurityPolicyParsers.h"
     53 #include "platform/network/ContentSecurityPolicyResponseHeaders.h"
     54 #include "platform/network/FormData.h"
     55 #include "platform/network/ResourceResponse.h"
     56 #include "platform/weborigin/KURL.h"
     57 #include "platform/weborigin/KnownPorts.h"
     58 #include "platform/weborigin/SchemeRegistry.h"
     59 #include "platform/weborigin/SecurityOrigin.h"
     60 #include "public/platform/Platform.h"
     61 #include "public/platform/WebArrayBuffer.h"
     62 #include "public/platform/WebCrypto.h"
     63 #include "public/platform/WebCryptoAlgorithm.h"
     64 #include "wtf/StringHasher.h"
     65 #include "wtf/text/StringBuilder.h"
     66 #include "wtf/text/StringUTF8Adaptor.h"
     67 
     68 namespace blink {
     69 
     70 // CSP 1.0 Directives
     71 const char ContentSecurityPolicy::ConnectSrc[] = "connect-src";
     72 const char ContentSecurityPolicy::DefaultSrc[] = "default-src";
     73 const char ContentSecurityPolicy::FontSrc[] = "font-src";
     74 const char ContentSecurityPolicy::FrameSrc[] = "frame-src";
     75 const char ContentSecurityPolicy::ImgSrc[] = "img-src";
     76 const char ContentSecurityPolicy::MediaSrc[] = "media-src";
     77 const char ContentSecurityPolicy::ObjectSrc[] = "object-src";
     78 const char ContentSecurityPolicy::ReportURI[] = "report-uri";
     79 const char ContentSecurityPolicy::Sandbox[] = "sandbox";
     80 const char ContentSecurityPolicy::ScriptSrc[] = "script-src";
     81 const char ContentSecurityPolicy::StyleSrc[] = "style-src";
     82 
     83 // CSP 1.1 Directives
     84 const char ContentSecurityPolicy::BaseURI[] = "base-uri";
     85 const char ContentSecurityPolicy::ChildSrc[] = "child-src";
     86 const char ContentSecurityPolicy::FormAction[] = "form-action";
     87 const char ContentSecurityPolicy::FrameAncestors[] = "frame-ancestors";
     88 const char ContentSecurityPolicy::PluginTypes[] = "plugin-types";
     89 const char ContentSecurityPolicy::ReflectedXSS[] = "reflected-xss";
     90 const char ContentSecurityPolicy::Referrer[] = "referrer";
     91 
     92 bool ContentSecurityPolicy::isDirectiveName(const String& name)
     93 {
     94     return (equalIgnoringCase(name, ConnectSrc)
     95         || equalIgnoringCase(name, DefaultSrc)
     96         || equalIgnoringCase(name, FontSrc)
     97         || equalIgnoringCase(name, FrameSrc)
     98         || equalIgnoringCase(name, ImgSrc)
     99         || equalIgnoringCase(name, MediaSrc)
    100         || equalIgnoringCase(name, ObjectSrc)
    101         || equalIgnoringCase(name, ReportURI)
    102         || equalIgnoringCase(name, Sandbox)
    103         || equalIgnoringCase(name, ScriptSrc)
    104         || equalIgnoringCase(name, StyleSrc)
    105         || equalIgnoringCase(name, BaseURI)
    106         || equalIgnoringCase(name, ChildSrc)
    107         || equalIgnoringCase(name, FormAction)
    108         || equalIgnoringCase(name, FrameAncestors)
    109         || equalIgnoringCase(name, PluginTypes)
    110         || equalIgnoringCase(name, ReflectedXSS)
    111         || equalIgnoringCase(name, Referrer)
    112     );
    113 }
    114 
    115 static UseCounter::Feature getUseCounterType(ContentSecurityPolicyHeaderType type)
    116 {
    117     switch (type) {
    118     case ContentSecurityPolicyHeaderTypeEnforce:
    119         return UseCounter::ContentSecurityPolicy;
    120     case ContentSecurityPolicyHeaderTypeReport:
    121         return UseCounter::ContentSecurityPolicyReportOnly;
    122     }
    123     ASSERT_NOT_REACHED();
    124     return UseCounter::NumberOfFeatures;
    125 }
    126 
    127 static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b)
    128 {
    129     if (a != b)
    130         return ReferrerPolicyNever;
    131     return a;
    132 }
    133 
    134 ContentSecurityPolicy::ContentSecurityPolicy()
    135     : m_executionContext(0)
    136     , m_overrideInlineStyleAllowed(false)
    137     , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone)
    138     , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone)
    139     , m_sandboxMask(0)
    140     , m_referrerPolicy(ReferrerPolicyDefault)
    141 {
    142 }
    143 
    144 void ContentSecurityPolicy::bindToExecutionContext(ExecutionContext* executionContext)
    145 {
    146     m_executionContext = executionContext;
    147     applyPolicySideEffectsToExecutionContext();
    148 }
    149 
    150 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext()
    151 {
    152     ASSERT(m_executionContext);
    153     // Ensure that 'self' processes correctly.
    154     m_selfSource = adoptPtr(new CSPSource(this, securityOrigin()->protocol(), securityOrigin()->host(), securityOrigin()->port(), String(), CSPSource::NoWildcard, CSPSource::NoWildcard));
    155 
    156     // If we're in a Document, set the referrer policy and sandbox flags, then dump all the
    157     // parsing error messages, then poke at histograms.
    158     if (Document* document = this->document()) {
    159         document->enforceSandboxFlags(m_sandboxMask);
    160         if (didSetReferrerPolicy())
    161             document->setReferrerPolicy(m_referrerPolicy);
    162 
    163         for (ConsoleMessageVector::const_iterator iter = m_consoleMessages.begin(); iter != m_consoleMessages.end(); ++iter)
    164             m_executionContext->addConsoleMessage(*iter);
    165         m_consoleMessages.clear();
    166 
    167         for (CSPDirectiveListVector::const_iterator iter = m_policies.begin(); iter != m_policies.end(); ++iter)
    168             UseCounter::count(*document, getUseCounterType((*iter)->headerType()));
    169     }
    170 
    171     // We disable 'eval()' even in the case of report-only policies, and rely on the check in the
    172     // V8Initializer::codeGenerationCheckCallbackInMainThread callback to determine whether the
    173     // call should execute or not.
    174     if (!m_disableEvalErrorMessage.isNull())
    175         m_executionContext->disableEval(m_disableEvalErrorMessage);
    176 }
    177 
    178 ContentSecurityPolicy::~ContentSecurityPolicy()
    179 {
    180 }
    181 
    182 Document* ContentSecurityPolicy::document() const
    183 {
    184     return m_executionContext->isDocument() ? toDocument(m_executionContext) : 0;
    185 }
    186 
    187 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other)
    188 {
    189     ASSERT(m_policies.isEmpty());
    190     for (CSPDirectiveListVector::const_iterator iter = other->m_policies.begin(); iter != other->m_policies.end(); ++iter)
    191         addPolicyFromHeaderValue((*iter)->header(), (*iter)->headerType(), (*iter)->headerSource());
    192 }
    193 
    194 void ContentSecurityPolicy::didReceiveHeaders(const ContentSecurityPolicyResponseHeaders& headers)
    195 {
    196     if (!headers.contentSecurityPolicy().isEmpty())
    197         addPolicyFromHeaderValue(headers.contentSecurityPolicy(), ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
    198     if (!headers.contentSecurityPolicyReportOnly().isEmpty())
    199         addPolicyFromHeaderValue(headers.contentSecurityPolicyReportOnly(), ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
    200 }
    201 
    202 void ContentSecurityPolicy::didReceiveHeader(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
    203 {
    204     addPolicyFromHeaderValue(header, type, source);
    205 
    206     // This might be called after we've been bound to an execution context. For example, a <meta>
    207     // element might be injected after page load.
    208     if (m_executionContext)
    209         applyPolicySideEffectsToExecutionContext();
    210 }
    211 
    212 void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
    213 {
    214     // If this is a report-only header inside a <meta> element, bail out.
    215     if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecurityPolicyHeaderTypeReport && experimentalFeaturesEnabled()) {
    216         reportReportOnlyInMeta(header);
    217         return;
    218     }
    219 
    220     Vector<UChar> characters;
    221     header.appendTo(characters);
    222 
    223     const UChar* begin = characters.data();
    224     const UChar* end = begin + characters.size();
    225 
    226     // RFC2616, section 4.2 specifies that headers appearing multiple times can
    227     // be combined with a comma. Walk the header string, and parse each comma
    228     // separated chunk as a separate header.
    229     const UChar* position = begin;
    230     while (position < end) {
    231         skipUntil<UChar>(position, end, ',');
    232 
    233         // header1,header2 OR header1
    234         //        ^                  ^
    235         OwnPtr<CSPDirectiveList> policy = CSPDirectiveList::create(this, begin, position, type, source);
    236 
    237         if (type != ContentSecurityPolicyHeaderTypeReport && policy->didSetReferrerPolicy()) {
    238             // FIXME: We need a 'ReferrerPolicyUnset' enum to avoid confusing code like this.
    239             m_referrerPolicy = didSetReferrerPolicy() ? mergeReferrerPolicies(m_referrerPolicy, policy->referrerPolicy()) : policy->referrerPolicy();
    240         }
    241 
    242         if (!policy->allowEval(0, SuppressReport) && m_disableEvalErrorMessage.isNull())
    243             m_disableEvalErrorMessage = policy->evalDisabledErrorMessage();
    244 
    245         m_policies.append(policy.release());
    246 
    247         // Skip the comma, and begin the next header from the current position.
    248         ASSERT(position == end || *position == ',');
    249         skipExactly<UChar>(position, end, ',');
    250         begin = position;
    251     }
    252 }
    253 
    254 void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value)
    255 {
    256     m_overrideInlineStyleAllowed = value;
    257 }
    258 
    259 void ContentSecurityPolicy::setOverrideURLForSelf(const KURL& url)
    260 {
    261     // Create a temporary CSPSource so that 'self' expressions can be resolved before we bind to
    262     // an execution context (for 'frame-ancestor' resolution, for example). This CSPSource will
    263     // be overwritten when we bind this object to an execution context.
    264     RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
    265     m_selfSource = adoptPtr(new CSPSource(this, origin->protocol(), origin->host(), origin->port(), String(), CSPSource::NoWildcard, CSPSource::NoWildcard));
    266 }
    267 
    268 const String& ContentSecurityPolicy::deprecatedHeader() const
    269 {
    270     return m_policies.isEmpty() ? emptyString() : m_policies[0]->header();
    271 }
    272 
    273 ContentSecurityPolicyHeaderType ContentSecurityPolicy::deprecatedHeaderType() const
    274 {
    275     return m_policies.isEmpty() ? ContentSecurityPolicyHeaderTypeEnforce : m_policies[0]->headerType();
    276 }
    277 
    278 template<bool (CSPDirectiveList::*allowed)(ContentSecurityPolicy::ReportingStatus) const>
    279 bool isAllowedByAll(const CSPDirectiveListVector& policies, ContentSecurityPolicy::ReportingStatus reportingStatus)
    280 {
    281     for (size_t i = 0; i < policies.size(); ++i) {
    282         if (!(policies[i].get()->*allowed)(reportingStatus))
    283             return false;
    284     }
    285     return true;
    286 }
    287 
    288 template<bool (CSPDirectiveList::*allowed)(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus) const>
    289 bool isAllowedByAllWithState(const CSPDirectiveListVector& policies, ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus)
    290 {
    291     for (size_t i = 0; i < policies.size(); ++i) {
    292         if (!(policies[i].get()->*allowed)(scriptState, reportingStatus))
    293             return false;
    294     }
    295     return true;
    296 }
    297 
    298 template<bool (CSPDirectiveList::*allowed)(const String&, const WTF::OrdinalNumber&, ContentSecurityPolicy::ReportingStatus) const>
    299 bool isAllowedByAllWithContext(const CSPDirectiveListVector& policies, const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus)
    300 {
    301     for (size_t i = 0; i < policies.size(); ++i) {
    302         if (!(policies[i].get()->*allowed)(contextURL, contextLine, reportingStatus))
    303             return false;
    304     }
    305     return true;
    306 }
    307 
    308 template<bool (CSPDirectiveList::*allowed)(const String&) const>
    309 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const String& nonce)
    310 {
    311     for (size_t i = 0; i < policies.size(); ++i) {
    312         if (!(policies[i].get()->*allowed)(nonce))
    313             return false;
    314     }
    315     return true;
    316 }
    317 
    318 template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
    319 bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const CSPHashValue& hashValue)
    320 {
    321     for (size_t i = 0; i < policies.size(); ++i) {
    322         if (!(policies[i].get()->*allowed)(hashValue))
    323             return false;
    324     }
    325     return true;
    326 }
    327 
    328 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPolicy::ReportingStatus) const>
    329 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus)
    330 {
    331     if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
    332         return true;
    333 
    334     for (size_t i = 0; i < policies.size(); ++i) {
    335         if (!(policies[i].get()->*allowFromURL)(url, reportingStatus))
    336             return false;
    337     }
    338     return true;
    339 }
    340 
    341 template<bool (CSPDirectiveList::*allowed)(LocalFrame*, const KURL&, ContentSecurityPolicy::ReportingStatus) const>
    342 bool isAllowedByAllWithFrame(const CSPDirectiveListVector& policies, LocalFrame* frame, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus)
    343 {
    344     for (size_t i = 0; i < policies.size(); ++i) {
    345         if (!(policies[i].get()->*allowed)(frame, url, reportingStatus))
    346             return false;
    347     }
    348     return true;
    349 }
    350 
    351 template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
    352 bool checkDigest(const String& source, uint8_t hashAlgorithmsUsed, const CSPDirectiveListVector& policies)
    353 {
    354     // Any additions or subtractions from this struct should also modify the
    355     // respective entries in the kSupportedPrefixes array in
    356     // CSPSourceList::parseHash().
    357     static const struct {
    358         ContentSecurityPolicyHashAlgorithm cspHashAlgorithm;
    359         HashAlgorithm algorithm;
    360     } kAlgorithmMap[] = {
    361         { ContentSecurityPolicyHashAlgorithmSha1, HashAlgorithmSha1 },
    362         { ContentSecurityPolicyHashAlgorithmSha256, HashAlgorithmSha256 },
    363         { ContentSecurityPolicyHashAlgorithmSha384, HashAlgorithmSha384 },
    364         { ContentSecurityPolicyHashAlgorithmSha512, HashAlgorithmSha512 }
    365     };
    366 
    367     // Only bother normalizing the source/computing digests if there are any checks to be done.
    368     if (hashAlgorithmsUsed == ContentSecurityPolicyHashAlgorithmNone)
    369         return false;
    370 
    371     StringUTF8Adaptor normalizedSource(source, StringUTF8Adaptor::Normalize, WTF::EntitiesForUnencodables);
    372 
    373     // See comment in CSPSourceList::parseHash about why we are using this sizeof
    374     // calculation instead of WTF_ARRAY_LENGTH.
    375     for (size_t i = 0; i < (sizeof(kAlgorithmMap) / sizeof(kAlgorithmMap[0])); i++) {
    376         DigestValue digest;
    377         if (kAlgorithmMap[i].cspHashAlgorithm & hashAlgorithmsUsed) {
    378             bool digestSuccess = computeDigest(kAlgorithmMap[i].algorithm, normalizedSource.data(), normalizedSource.length(), digest);
    379             if (digestSuccess && isAllowedByAllWithHash<allowed>(policies, CSPHashValue(kAlgorithmMap[i].cspHashAlgorithm, digest)))
    380                 return true;
    381         }
    382     }
    383 
    384     return false;
    385 }
    386 
    387 bool ContentSecurityPolicy::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    388 {
    389     return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(m_policies, contextURL, contextLine, reportingStatus);
    390 }
    391 
    392 bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    393 {
    394     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineEventHandlers>(m_policies, contextURL, contextLine, reportingStatus);
    395 }
    396 
    397 bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    398 {
    399     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
    400 }
    401 
    402 bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    403 {
    404     if (m_overrideInlineStyleAllowed)
    405         return true;
    406     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
    407 }
    408 
    409 bool ContentSecurityPolicy::allowEval(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    410 {
    411     return isAllowedByAllWithState<&CSPDirectiveList::allowEval>(m_policies, scriptState, reportingStatus);
    412 }
    413 
    414 String ContentSecurityPolicy::evalDisabledErrorMessage() const
    415 {
    416     for (size_t i = 0; i < m_policies.size(); ++i) {
    417         if (!m_policies[i]->allowEval(0, SuppressReport))
    418             return m_policies[i]->evalDisabledErrorMessage();
    419     }
    420     return String();
    421 }
    422 
    423 bool ContentSecurityPolicy::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    424 {
    425     for (size_t i = 0; i < m_policies.size(); ++i) {
    426         if (!m_policies[i]->allowPluginType(type, typeAttribute, url, reportingStatus))
    427             return false;
    428     }
    429     return true;
    430 }
    431 
    432 bool ContentSecurityPolicy::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    433 {
    434     return isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, reportingStatus);
    435 }
    436 
    437 bool ContentSecurityPolicy::allowScriptWithNonce(const String& nonce) const
    438 {
    439     return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_policies, nonce);
    440 }
    441 
    442 bool ContentSecurityPolicy::allowStyleWithNonce(const String& nonce) const
    443 {
    444     return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policies, nonce);
    445 }
    446 
    447 bool ContentSecurityPolicy::allowScriptWithHash(const String& source) const
    448 {
    449     return checkDigest<&CSPDirectiveList::allowScriptHash>(source, m_scriptHashAlgorithmsUsed, m_policies);
    450 }
    451 
    452 bool ContentSecurityPolicy::allowStyleWithHash(const String& source) const
    453 {
    454     return checkDigest<&CSPDirectiveList::allowStyleHash>(source, m_styleHashAlgorithmsUsed, m_policies);
    455 }
    456 
    457 void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms)
    458 {
    459     m_scriptHashAlgorithmsUsed |= algorithms;
    460 }
    461 
    462 void ContentSecurityPolicy::usesStyleHashAlgorithms(uint8_t algorithms)
    463 {
    464     m_styleHashAlgorithmsUsed |= algorithms;
    465 }
    466 
    467 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    468 {
    469     return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_policies, url, reportingStatus);
    470 }
    471 
    472 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    473 {
    474     return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m_policies, url, reportingStatus);
    475 }
    476 
    477 bool ContentSecurityPolicy::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    478 {
    479     return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(m_policies, url, reportingStatus);
    480 }
    481 
    482 bool ContentSecurityPolicy::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    483 {
    484     return isAllowedByAllWithURL<&CSPDirectiveList::allowStyleFromSource>(m_policies, url, reportingStatus);
    485 }
    486 
    487 bool ContentSecurityPolicy::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    488 {
    489     return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(m_policies, url, reportingStatus);
    490 }
    491 
    492 bool ContentSecurityPolicy::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    493 {
    494     return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(m_policies, url, reportingStatus);
    495 }
    496 
    497 bool ContentSecurityPolicy::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    498 {
    499     return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(m_policies, url, reportingStatus);
    500 }
    501 
    502 bool ContentSecurityPolicy::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    503 {
    504     return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(m_policies, url, reportingStatus);
    505 }
    506 
    507 bool ContentSecurityPolicy::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    508 {
    509     return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(m_policies, url, reportingStatus);
    510 }
    511 
    512 bool ContentSecurityPolicy::allowAncestors(LocalFrame* frame, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    513 {
    514     return isAllowedByAllWithFrame<&CSPDirectiveList::allowAncestors>(m_policies, frame, url, reportingStatus);
    515 }
    516 
    517 bool ContentSecurityPolicy::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    518 {
    519     return isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, reportingStatus);
    520 }
    521 
    522 bool ContentSecurityPolicy::allowWorkerContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    523 {
    524     // CSP 1.1 moves workers from 'script-src' to the new 'child-src'. Measure the impact of this backwards-incompatible change.
    525     if (Document* document = this->document()) {
    526         UseCounter::count(*document, UseCounter::WorkerSubjectToCSP);
    527         if (isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, SuppressReport) && !isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, SuppressReport))
    528             UseCounter::count(*document, UseCounter::WorkerAllowedByChildBlockedByScript);
    529     }
    530 
    531     return experimentalFeaturesEnabled() ?
    532         isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, reportingStatus) :
    533         isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, reportingStatus);
    534 }
    535 
    536 bool ContentSecurityPolicy::isActive() const
    537 {
    538     return !m_policies.isEmpty();
    539 }
    540 
    541 ReflectedXSSDisposition ContentSecurityPolicy::reflectedXSSDisposition() const
    542 {
    543     ReflectedXSSDisposition disposition = ReflectedXSSUnset;
    544     for (size_t i = 0; i < m_policies.size(); ++i) {
    545         if (m_policies[i]->reflectedXSSDisposition() > disposition)
    546             disposition = std::max(disposition, m_policies[i]->reflectedXSSDisposition());
    547     }
    548     return disposition;
    549 }
    550 
    551 ReferrerPolicy ContentSecurityPolicy::referrerPolicy() const
    552 {
    553     ReferrerPolicy policy = ReferrerPolicyDefault;
    554     bool first = true;
    555     for (size_t i = 0; i < m_policies.size(); ++i) {
    556         if (m_policies[i]->didSetReferrerPolicy()) {
    557             if (first)
    558                 policy = m_policies[i]->referrerPolicy();
    559             else
    560                 policy = mergeReferrerPolicies(policy, m_policies[i]->referrerPolicy());
    561         }
    562     }
    563     return policy;
    564 }
    565 
    566 bool ContentSecurityPolicy::didSetReferrerPolicy() const
    567 {
    568     for (size_t i = 0; i < m_policies.size(); ++i) {
    569         if (m_policies[i]->didSetReferrerPolicy())
    570             return true;
    571     }
    572     return false;
    573 }
    574 
    575 SecurityOrigin* ContentSecurityPolicy::securityOrigin() const
    576 {
    577     return m_executionContext->securityContext().securityOrigin();
    578 }
    579 
    580 const KURL ContentSecurityPolicy::url() const
    581 {
    582     return m_executionContext->contextURL();
    583 }
    584 
    585 KURL ContentSecurityPolicy::completeURL(const String& url) const
    586 {
    587     return m_executionContext->contextCompleteURL(url);
    588 }
    589 
    590 void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask)
    591 {
    592     m_sandboxMask |= mask;
    593 }
    594 
    595 static String stripURLForUseInReport(Document* document, const KURL& url)
    596 {
    597     if (!url.isValid())
    598         return String();
    599     if (!url.isHierarchical() || url.protocolIs("file"))
    600         return url.protocol();
    601     return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsReferrer() : SecurityOrigin::create(url)->toString();
    602 }
    603 
    604 static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventInit& init, Document* document, const String& directiveText, const String& effectiveDirective, const KURL& blockedURL, const String& header)
    605 {
    606     if (equalIgnoringCase(effectiveDirective, ContentSecurityPolicy::FrameAncestors)) {
    607         // If this load was blocked via 'frame-ancestors', then the URL of |document| has not yet
    608         // been initialized. In this case, we'll set both 'documentURI' and 'blockedURI' to the
    609         // blocked document's URL.
    610         init.documentURI = blockedURL.string();
    611         init.blockedURI = blockedURL.string();
    612     } else {
    613         init.documentURI = document->url().string();
    614         init.blockedURI = stripURLForUseInReport(document, blockedURL);
    615     }
    616     init.referrer = document->referrer();
    617     init.violatedDirective = directiveText;
    618     init.effectiveDirective = effectiveDirective;
    619     init.originalPolicy = header;
    620     init.sourceFile = String();
    621     init.lineNumber = 0;
    622     init.columnNumber = 0;
    623     init.statusCode = 0;
    624 
    625     if (!SecurityOrigin::isSecure(document->url()) && document->loader())
    626         init.statusCode = document->loader()->response().httpStatusCode();
    627 
    628     RefPtrWillBeRawPtr<ScriptCallStack> stack = createScriptCallStack(1, false);
    629     if (!stack)
    630         return;
    631 
    632     const ScriptCallFrame& callFrame = stack->at(0);
    633 
    634     if (callFrame.lineNumber()) {
    635         KURL source = KURL(ParsedURLString, callFrame.sourceURL());
    636         init.sourceFile = stripURLForUseInReport(document, source);
    637         init.lineNumber = callFrame.lineNumber();
    638         init.columnNumber = callFrame.columnNumber();
    639     }
    640 }
    641 
    642 void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<String>& reportEndpoints, const String& header, LocalFrame* contextFrame)
    643 {
    644     ASSERT((m_executionContext && !contextFrame) || (equalIgnoringCase(effectiveDirective, ContentSecurityPolicy::FrameAncestors) && contextFrame));
    645 
    646     // FIXME: Support sending reports from worker.
    647     Document* document = contextFrame ? contextFrame->document() : this->document();
    648     if (!document)
    649         return;
    650 
    651     LocalFrame* frame = document->frame();
    652     if (!frame)
    653         return;
    654 
    655     SecurityPolicyViolationEventInit violationData;
    656     gatherSecurityPolicyViolationEventData(violationData, document, directiveText, effectiveDirective, blockedURL, header);
    657 
    658     if (experimentalFeaturesEnabled())
    659         frame->domWindow()->enqueueDocumentEvent(SecurityPolicyViolationEvent::create(EventTypeNames::securitypolicyviolation, violationData));
    660 
    661     if (reportEndpoints.isEmpty())
    662         return;
    663 
    664     // We need to be careful here when deciding what information to send to the
    665     // report-uri. Currently, we send only the current document's URL and the
    666     // directive that was violated. The document's URL is safe to send because
    667     // it's the document itself that's requesting that it be sent. You could
    668     // make an argument that we shouldn't send HTTPS document URLs to HTTP
    669     // report-uris (for the same reasons that we supress the Referer in that
    670     // case), but the Referer is sent implicitly whereas this request is only
    671     // sent explicitly. As for which directive was violated, that's pretty
    672     // harmless information.
    673 
    674     RefPtr<JSONObject> cspReport = JSONObject::create();
    675     cspReport->setString("document-uri", violationData.documentURI);
    676     cspReport->setString("referrer", violationData.referrer);
    677     cspReport->setString("violated-directive", violationData.violatedDirective);
    678     if (experimentalFeaturesEnabled())
    679         cspReport->setString("effective-directive", violationData.effectiveDirective);
    680     cspReport->setString("original-policy", violationData.originalPolicy);
    681     cspReport->setString("blocked-uri", violationData.blockedURI);
    682     if (!violationData.sourceFile.isEmpty() && violationData.lineNumber) {
    683         cspReport->setString("source-file", violationData.sourceFile);
    684         cspReport->setNumber("line-number", violationData.lineNumber);
    685         cspReport->setNumber("column-number", violationData.columnNumber);
    686     }
    687     cspReport->setNumber("status-code", violationData.statusCode);
    688 
    689     RefPtr<JSONObject> reportObject = JSONObject::create();
    690     reportObject->setObject("csp-report", cspReport.release());
    691     String stringifiedReport = reportObject->toJSONString();
    692 
    693     if (!shouldSendViolationReport(stringifiedReport))
    694         return;
    695 
    696     RefPtr<FormData> report = FormData::create(stringifiedReport.utf8());
    697 
    698     for (size_t i = 0; i < reportEndpoints.size(); ++i) {
    699         // If we have a context frame we're dealing with 'frame-ancestors' and we don't have our
    700         // own execution context. Use the frame's document to complete the endpoint URL, overriding
    701         // its URL with the blocked document's URL.
    702         ASSERT(!contextFrame || !m_executionContext);
    703         ASSERT(!contextFrame || equalIgnoringCase(effectiveDirective, FrameAncestors));
    704         KURL endpoint = contextFrame ? frame->document()->completeURLWithOverride(reportEndpoints[i], blockedURL) : completeURL(reportEndpoints[i]);
    705         PingLoader::sendViolationReport(frame, completeURL(reportEndpoints[i]), report, PingLoader::ContentSecurityPolicyViolationReport);
    706     }
    707 
    708     didSendViolationReport(stringifiedReport);
    709 }
    710 
    711 void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue)
    712 {
    713     logToConsole("The 'referrer' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"never\", and \"origin\".");
    714 }
    715 
    716 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header)
    717 {
    718     logToConsole("The report-only Content Security Policy '" + header + "' was delivered via a <meta> element, which is disallowed. The policy has been ignored.");
    719 }
    720 
    721 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header)
    722 {
    723     logToConsole("The Content Security Policy '" + header + "' was delivered via a <meta> element outside the document's <head>, which is disallowed. The policy has been ignored.");
    724 }
    725 
    726 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name)
    727 {
    728     logToConsole("The Content Security Policy directive '" + name + "' is ignored when delivered in a report-only policy.");
    729 }
    730 
    731 void ContentSecurityPolicy::reportUnsupportedDirective(const String& name)
    732 {
    733     DEFINE_STATIC_LOCAL(String, allow, ("allow"));
    734     DEFINE_STATIC_LOCAL(String, options, ("options"));
    735     DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri"));
    736     DEFINE_STATIC_LOCAL(String, allowMessage, ("The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect."));
    737     DEFINE_STATIC_LOCAL(String, optionsMessage, ("The 'options' directive has been replaced with 'unsafe-inline' and 'unsafe-eval' source expressions for the 'script-src' and 'style-src' directives. Please use those directives instead, as 'options' has no effect."));
    738     DEFINE_STATIC_LOCAL(String, policyURIMessage, ("The 'policy-uri' directive has been removed from the specification. Please specify a complete policy via the Content-Security-Policy header."));
    739 
    740     String message = "Unrecognized Content-Security-Policy directive '" + name + "'.\n";
    741     MessageLevel level = ErrorMessageLevel;
    742     if (equalIgnoringCase(name, allow)) {
    743         message = allowMessage;
    744     } else if (equalIgnoringCase(name, options)) {
    745         message = optionsMessage;
    746     } else if (equalIgnoringCase(name, policyURI)) {
    747         message = policyURIMessage;
    748     } else if (isDirectiveName(name)) {
    749         message = "The Content-Security-Policy directive '" + name + "' is implemented behind a flag which is currently disabled.\n";
    750         level = InfoMessageLevel;
    751     }
    752 
    753     logToConsole(message, level);
    754 }
    755 
    756 void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression)
    757 {
    758     String message = "The Content Security Policy directive '" + directiveName + "' contains '" + sourceExpression + "' as a source expression. Did you mean '" + directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?";
    759     logToConsole(message);
    760 }
    761 
    762 void ContentSecurityPolicy::reportDuplicateDirective(const String& name)
    763 {
    764     String message = "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n";
    765     logToConsole(message);
    766 }
    767 
    768 void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType)
    769 {
    770     String message;
    771     if (pluginType.isNull())
    772         message = "'plugin-types' Content Security Policy directive is empty; all plugins will be blocked.\n";
    773     else
    774         message = "Invalid plugin type in 'plugin-types' Content Security Policy directive: '" + pluginType + "'.\n";
    775     logToConsole(message);
    776 }
    777 
    778 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags)
    779 {
    780     logToConsole("Error while parsing the 'sandbox' Content Security Policy directive: " + invalidFlags);
    781 }
    782 
    783 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue)
    784 {
    785     logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\", and \"block\".");
    786 }
    787 
    788 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value)
    789 {
    790     String message = "The value for Content Security Policy directive '" + directiveName + "' contains an invalid character: '" + value + "'. Non-whitespace characters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.";
    791     logToConsole(message);
    792 }
    793 
    794 void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveName, const String& value, const char invalidChar)
    795 {
    796     ASSERT(invalidChar == '#' || invalidChar == '?');
    797 
    798     String ignoring = "The fragment identifier, including the '#', will be ignored.";
    799     if (invalidChar == '?')
    800         ignoring = "The query component, including the '?', will be ignored.";
    801     String message = "The source list for Content Security Policy directive '" + directiveName + "' contains a source with an invalid path: '" + value + "'. " + ignoring;
    802     logToConsole(message);
    803 }
    804 
    805 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiveName, const String& source)
    806 {
    807     String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ignored.";
    808     if (equalIgnoringCase(source, "'none'"))
    809         message = message + " Note that 'none' has no effect unless it is the only expression in the source list.";
    810     logToConsole(message);
    811 }
    812 
    813 void ContentSecurityPolicy::reportMissingReportURI(const String& policy)
    814 {
    815     logToConsole("The Content Security Policy '" + policy + "' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header.");
    816 }
    817 
    818 void ContentSecurityPolicy::logToConsole(const String& message, MessageLevel level)
    819 {
    820     logToConsole(ConsoleMessage::create(SecurityMessageSource, level, message));
    821 }
    822 
    823 void ContentSecurityPolicy::logToConsole(PassRefPtrWillBeRawPtr<ConsoleMessage> consoleMessage, LocalFrame* frame)
    824 {
    825     if (frame)
    826         frame->document()->addConsoleMessage(consoleMessage);
    827     else if (m_executionContext)
    828         m_executionContext->addConsoleMessage(consoleMessage);
    829     else
    830         m_consoleMessages.append(consoleMessage);
    831 }
    832 
    833 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String& directiveText) const
    834 {
    835     m_executionContext->reportBlockedScriptExecutionToInspector(directiveText);
    836 }
    837 
    838 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const
    839 {
    840     return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnabled();
    841 }
    842 
    843 bool ContentSecurityPolicy::urlMatchesSelf(const KURL& url) const
    844 {
    845     return m_selfSource->matches(url);
    846 }
    847 
    848 bool ContentSecurityPolicy::protocolMatchesSelf(const KURL& url) const
    849 {
    850     String protectedResourceScheme(securityOrigin()->protocol());
    851     if (equalIgnoringCase("http", protectedResourceScheme))
    852         return url.protocolIsInHTTPFamily();
    853     return equalIgnoringCase(url.protocol(), protectedResourceScheme);
    854 }
    855 
    856 bool ContentSecurityPolicy::shouldBypassMainWorld(ExecutionContext* context)
    857 {
    858     if (context && context->isDocument()) {
    859         Document* document = toDocument(context);
    860         if (document->frame())
    861             return document->frame()->script().shouldBypassMainWorldCSP();
    862     }
    863     return false;
    864 }
    865 
    866 bool ContentSecurityPolicy::shouldSendViolationReport(const String& report) const
    867 {
    868     // Collisions have no security impact, so we can save space by storing only the string's hash rather than the whole report.
    869     return !m_violationReportsSent.contains(report.impl()->hash());
    870 }
    871 
    872 void ContentSecurityPolicy::didSendViolationReport(const String& report)
    873 {
    874     m_violationReportsSent.add(report.impl()->hash());
    875 }
    876 
    877 } // namespace blink
    878