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
isDirectiveName(const String & name)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
getUseCounterType(ContentSecurityPolicyHeaderType type)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
mergeReferrerPolicies(ReferrerPolicy a,ReferrerPolicy b)127 static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b)
128 {
129 if (a != b)
130 return ReferrerPolicyNever;
131 return a;
132 }
133
ContentSecurityPolicy()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
bindToExecutionContext(ExecutionContext * executionContext)144 void ContentSecurityPolicy::bindToExecutionContext(ExecutionContext* executionContext)
145 {
146 m_executionContext = executionContext;
147 applyPolicySideEffectsToExecutionContext();
148 }
149
applyPolicySideEffectsToExecutionContext()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
~ContentSecurityPolicy()178 ContentSecurityPolicy::~ContentSecurityPolicy()
179 {
180 }
181
document() const182 Document* ContentSecurityPolicy::document() const
183 {
184 return m_executionContext->isDocument() ? toDocument(m_executionContext) : 0;
185 }
186
copyStateFrom(const ContentSecurityPolicy * other)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
didReceiveHeaders(const ContentSecurityPolicyResponseHeaders & headers)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
didReceiveHeader(const String & header,ContentSecurityPolicyHeaderType type,ContentSecurityPolicyHeaderSource source)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
addPolicyFromHeaderValue(const String & header,ContentSecurityPolicyHeaderType type,ContentSecurityPolicyHeaderSource source)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
setOverrideAllowInlineStyle(bool value)254 void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value)
255 {
256 m_overrideInlineStyleAllowed = value;
257 }
258
setOverrideURLForSelf(const KURL & url)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
deprecatedHeader() const268 const String& ContentSecurityPolicy::deprecatedHeader() const
269 {
270 return m_policies.isEmpty() ? emptyString() : m_policies[0]->header();
271 }
272
deprecatedHeaderType() const273 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>
isAllowedByAll(const CSPDirectiveListVector & policies,ContentSecurityPolicy::ReportingStatus reportingStatus)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>
isAllowedByAllWithState(const CSPDirectiveListVector & policies,ScriptState * scriptState,ContentSecurityPolicy::ReportingStatus reportingStatus)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>
isAllowedByAllWithContext(const CSPDirectiveListVector & policies,const String & contextURL,const WTF::OrdinalNumber & contextLine,ContentSecurityPolicy::ReportingStatus reportingStatus)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>
isAllowedByAllWithNonce(const CSPDirectiveListVector & policies,const String & nonce)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>
isAllowedByAllWithHash(const CSPDirectiveListVector & policies,const CSPHashValue & hashValue)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>
isAllowedByAllWithURL(const CSPDirectiveListVector & policies,const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus)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>
isAllowedByAllWithFrame(const CSPDirectiveListVector & policies,LocalFrame * frame,const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus)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>
checkDigest(const String & source,uint8_t hashAlgorithmsUsed,const CSPDirectiveListVector & policies)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
allowJavaScriptURLs(const String & contextURL,const WTF::OrdinalNumber & contextLine,ContentSecurityPolicy::ReportingStatus reportingStatus) const387 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
allowInlineEventHandlers(const String & contextURL,const WTF::OrdinalNumber & contextLine,ContentSecurityPolicy::ReportingStatus reportingStatus) const392 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
allowInlineScript(const String & contextURL,const WTF::OrdinalNumber & contextLine,ContentSecurityPolicy::ReportingStatus reportingStatus) const397 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
allowInlineStyle(const String & contextURL,const WTF::OrdinalNumber & contextLine,ContentSecurityPolicy::ReportingStatus reportingStatus) const402 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
allowEval(ScriptState * scriptState,ContentSecurityPolicy::ReportingStatus reportingStatus) const409 bool ContentSecurityPolicy::allowEval(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus) const
410 {
411 return isAllowedByAllWithState<&CSPDirectiveList::allowEval>(m_policies, scriptState, reportingStatus);
412 }
413
evalDisabledErrorMessage() const414 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
allowPluginType(const String & type,const String & typeAttribute,const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const423 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
allowScriptFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const432 bool ContentSecurityPolicy::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
433 {
434 return isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, reportingStatus);
435 }
436
allowScriptWithNonce(const String & nonce) const437 bool ContentSecurityPolicy::allowScriptWithNonce(const String& nonce) const
438 {
439 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_policies, nonce);
440 }
441
allowStyleWithNonce(const String & nonce) const442 bool ContentSecurityPolicy::allowStyleWithNonce(const String& nonce) const
443 {
444 return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policies, nonce);
445 }
446
allowScriptWithHash(const String & source) const447 bool ContentSecurityPolicy::allowScriptWithHash(const String& source) const
448 {
449 return checkDigest<&CSPDirectiveList::allowScriptHash>(source, m_scriptHashAlgorithmsUsed, m_policies);
450 }
451
allowStyleWithHash(const String & source) const452 bool ContentSecurityPolicy::allowStyleWithHash(const String& source) const
453 {
454 return checkDigest<&CSPDirectiveList::allowStyleHash>(source, m_styleHashAlgorithmsUsed, m_policies);
455 }
456
usesScriptHashAlgorithms(uint8_t algorithms)457 void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms)
458 {
459 m_scriptHashAlgorithmsUsed |= algorithms;
460 }
461
usesStyleHashAlgorithms(uint8_t algorithms)462 void ContentSecurityPolicy::usesStyleHashAlgorithms(uint8_t algorithms)
463 {
464 m_styleHashAlgorithmsUsed |= algorithms;
465 }
466
allowObjectFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const467 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
468 {
469 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_policies, url, reportingStatus);
470 }
471
allowChildFrameFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const472 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
473 {
474 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m_policies, url, reportingStatus);
475 }
476
allowImageFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const477 bool ContentSecurityPolicy::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
478 {
479 return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(m_policies, url, reportingStatus);
480 }
481
allowStyleFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const482 bool ContentSecurityPolicy::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
483 {
484 return isAllowedByAllWithURL<&CSPDirectiveList::allowStyleFromSource>(m_policies, url, reportingStatus);
485 }
486
allowFontFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const487 bool ContentSecurityPolicy::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
488 {
489 return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(m_policies, url, reportingStatus);
490 }
491
allowMediaFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const492 bool ContentSecurityPolicy::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
493 {
494 return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(m_policies, url, reportingStatus);
495 }
496
allowConnectToSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const497 bool ContentSecurityPolicy::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
498 {
499 return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(m_policies, url, reportingStatus);
500 }
501
allowFormAction(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const502 bool ContentSecurityPolicy::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
503 {
504 return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(m_policies, url, reportingStatus);
505 }
506
allowBaseURI(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const507 bool ContentSecurityPolicy::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
508 {
509 return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(m_policies, url, reportingStatus);
510 }
511
allowAncestors(LocalFrame * frame,const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const512 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
allowChildContextFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const517 bool ContentSecurityPolicy::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
518 {
519 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, reportingStatus);
520 }
521
allowWorkerContextFromSource(const KURL & url,ContentSecurityPolicy::ReportingStatus reportingStatus) const522 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
isActive() const536 bool ContentSecurityPolicy::isActive() const
537 {
538 return !m_policies.isEmpty();
539 }
540
reflectedXSSDisposition() const541 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
referrerPolicy() const551 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
didSetReferrerPolicy() const566 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
securityOrigin() const575 SecurityOrigin* ContentSecurityPolicy::securityOrigin() const
576 {
577 return m_executionContext->securityContext().securityOrigin();
578 }
579
url() const580 const KURL ContentSecurityPolicy::url() const
581 {
582 return m_executionContext->contextURL();
583 }
584
completeURL(const String & url) const585 KURL ContentSecurityPolicy::completeURL(const String& url) const
586 {
587 return m_executionContext->contextCompleteURL(url);
588 }
589
enforceSandboxFlags(SandboxFlags mask)590 void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask)
591 {
592 m_sandboxMask |= mask;
593 }
594
stripURLForUseInReport(Document * document,const KURL & url)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
gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventInit & init,Document * document,const String & directiveText,const String & effectiveDirective,const KURL & blockedURL,const String & header)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
reportViolation(const String & directiveText,const String & effectiveDirective,const String & consoleMessage,const KURL & blockedURL,const Vector<String> & reportEndpoints,const String & header,LocalFrame * contextFrame)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
reportInvalidReferrer(const String & invalidValue)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
reportReportOnlyInMeta(const String & header)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
reportMetaOutsideHead(const String & header)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
reportInvalidInReportOnly(const String & name)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
reportUnsupportedDirective(const String & name)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
reportDirectiveAsSourceExpression(const String & directiveName,const String & sourceExpression)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
reportDuplicateDirective(const String & name)762 void ContentSecurityPolicy::reportDuplicateDirective(const String& name)
763 {
764 String message = "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n";
765 logToConsole(message);
766 }
767
reportInvalidPluginTypes(const String & pluginType)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
reportInvalidSandboxFlags(const String & invalidFlags)778 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags)
779 {
780 logToConsole("Error while parsing the 'sandbox' Content Security Policy directive: " + invalidFlags);
781 }
782
reportInvalidReflectedXSS(const String & invalidValue)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
reportInvalidDirectiveValueCharacter(const String & directiveName,const String & value)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
reportInvalidPathCharacter(const String & directiveName,const String & value,const char invalidChar)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
reportInvalidSourceExpression(const String & directiveName,const String & source)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
reportMissingReportURI(const String & policy)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
logToConsole(const String & message,MessageLevel level)818 void ContentSecurityPolicy::logToConsole(const String& message, MessageLevel level)
819 {
820 logToConsole(ConsoleMessage::create(SecurityMessageSource, level, message));
821 }
822
logToConsole(PassRefPtrWillBeRawPtr<ConsoleMessage> consoleMessage,LocalFrame * frame)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
reportBlockedScriptExecutionToInspector(const String & directiveText) const833 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String& directiveText) const
834 {
835 m_executionContext->reportBlockedScriptExecutionToInspector(directiveText);
836 }
837
experimentalFeaturesEnabled() const838 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const
839 {
840 return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnabled();
841 }
842
urlMatchesSelf(const KURL & url) const843 bool ContentSecurityPolicy::urlMatchesSelf(const KURL& url) const
844 {
845 return m_selfSource->matches(url);
846 }
847
protocolMatchesSelf(const KURL & url) const848 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
shouldBypassMainWorld(ExecutionContext * context)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
shouldSendViolationReport(const String & report) const866 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
didSendViolationReport(const String & report)872 void ContentSecurityPolicy::didSendViolationReport(const String& report)
873 {
874 m_violationReportsSent.add(report.impl()->hash());
875 }
876
877 } // namespace blink
878