Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: Source/core/frame/ContentSecurityPolicy.cpp

Issue 180523003: Move ContentSecurityPolicy to core/frame/csp (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/frame/ContentSecurityPolicy.h ('k') | Source/core/frame/csp/CSPDirectiveList.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/ContentSecurityPolicy.h"
28
29 #include "RuntimeEnabledFeatures.h"
30 #include "bindings/v8/ScriptCallStackFactory.h"
31 #include "bindings/v8/ScriptController.h"
32 #include "core/dom/DOMStringList.h"
33 #include "core/dom/Document.h"
34 #include "core/events/SecurityPolicyViolationEvent.h"
35 #include "core/frame/DOMWindow.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/UseCounter.h"
38 #include "core/frame/csp/CSPDirectiveList.h"
39 #include "core/frame/csp/CSPSource.h"
40 #include "core/frame/csp/CSPSourceList.h"
41 #include "core/frame/csp/MediaListDirective.h"
42 #include "core/frame/csp/SourceListDirective.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/JSONValues.h"
48 #include "platform/NotImplemented.h"
49 #include "platform/ParsingUtilities.h"
50 #include "platform/network/ContentSecurityPolicyParsers.h"
51 #include "platform/network/ContentSecurityPolicyResponseHeaders.h"
52 #include "platform/network/FormData.h"
53 #include "platform/network/ResourceResponse.h"
54 #include "platform/weborigin/KURL.h"
55 #include "platform/weborigin/KnownPorts.h"
56 #include "platform/weborigin/SchemeRegistry.h"
57 #include "platform/weborigin/SecurityOrigin.h"
58 #include "public/platform/Platform.h"
59 #include "public/platform/WebArrayBuffer.h"
60 #include "public/platform/WebCrypto.h"
61 #include "public/platform/WebCryptoAlgorithm.h"
62 #include "wtf/HashMap.h"
63 #include "wtf/StringHasher.h"
64 #include "wtf/text/StringBuilder.h"
65
66 namespace WebCore {
67
68 // CSP 1.0 Directives
69 const char ContentSecurityPolicy::ConnectSrc[] = "connect-src";
70 const char ContentSecurityPolicy::DefaultSrc[] = "default-src";
71 const char ContentSecurityPolicy::FontSrc[] = "font-src";
72 const char ContentSecurityPolicy::FrameSrc[] = "frame-src";
73 const char ContentSecurityPolicy::ImgSrc[] = "img-src";
74 const char ContentSecurityPolicy::MediaSrc[] = "media-src";
75 const char ContentSecurityPolicy::ObjectSrc[] = "object-src";
76 const char ContentSecurityPolicy::ReportURI[] = "report-uri";
77 const char ContentSecurityPolicy::Sandbox[] = "sandbox";
78 const char ContentSecurityPolicy::ScriptSrc[] = "script-src";
79 const char ContentSecurityPolicy::StyleSrc[] = "style-src";
80
81 // CSP 1.1 Directives
82 const char ContentSecurityPolicy::BaseURI[] = "base-uri";
83 const char ContentSecurityPolicy::ChildSrc[] = "child-src";
84 const char ContentSecurityPolicy::FormAction[] = "form-action";
85 const char ContentSecurityPolicy::FrameAncestors[] = "frame-ancestors";
86 const char ContentSecurityPolicy::PluginTypes[] = "plugin-types";
87 const char ContentSecurityPolicy::ReflectedXSS[] = "reflected-xss";
88 const char ContentSecurityPolicy::Referrer[] = "referrer";
89
90 bool ContentSecurityPolicy::isDirectiveName(const String& name)
91 {
92 return (equalIgnoringCase(name, ConnectSrc)
93 || equalIgnoringCase(name, DefaultSrc)
94 || equalIgnoringCase(name, FontSrc)
95 || equalIgnoringCase(name, FrameSrc)
96 || equalIgnoringCase(name, ImgSrc)
97 || equalIgnoringCase(name, MediaSrc)
98 || equalIgnoringCase(name, ObjectSrc)
99 || equalIgnoringCase(name, ReportURI)
100 || equalIgnoringCase(name, Sandbox)
101 || equalIgnoringCase(name, ScriptSrc)
102 || equalIgnoringCase(name, StyleSrc)
103 || equalIgnoringCase(name, BaseURI)
104 || equalIgnoringCase(name, ChildSrc)
105 || equalIgnoringCase(name, FormAction)
106 || equalIgnoringCase(name, FrameAncestors)
107 || equalIgnoringCase(name, PluginTypes)
108 || equalIgnoringCase(name, ReflectedXSS)
109 || equalIgnoringCase(name, Referrer)
110 );
111 }
112
113 static UseCounter::Feature getUseCounterType(ContentSecurityPolicyHeaderType typ e)
114 {
115 switch (type) {
116 case ContentSecurityPolicyHeaderTypeEnforce:
117 return UseCounter::ContentSecurityPolicy;
118 case ContentSecurityPolicyHeaderTypeReport:
119 return UseCounter::ContentSecurityPolicyReportOnly;
120 }
121 ASSERT_NOT_REACHED();
122 return UseCounter::NumberOfFeatures;
123 }
124
125 static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b)
126 {
127 if (a != b)
128 return ReferrerPolicyNever;
129 return a;
130 }
131
132 ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContextClient* client)
133 : m_client(client)
134 , m_overrideInlineStyleAllowed(false)
135 , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone)
136 , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone)
137 {
138 }
139
140 ContentSecurityPolicy::~ContentSecurityPolicy()
141 {
142 }
143
144 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other)
145 {
146 ASSERT(m_policies.isEmpty());
147 for (CSPDirectiveListVector::const_iterator iter = other->m_policies.begin() ; iter != other->m_policies.end(); ++iter)
148 addPolicyFromHeaderValue((*iter)->header(), (*iter)->headerType(), (*ite r)->headerSource());
149 }
150
151 void ContentSecurityPolicy::didReceiveHeaders(const ContentSecurityPolicyRespons eHeaders& headers)
152 {
153 if (!headers.contentSecurityPolicy().isEmpty())
154 didReceiveHeader(headers.contentSecurityPolicy(), ContentSecurityPolicyH eaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
155 if (!headers.contentSecurityPolicyReportOnly().isEmpty())
156 didReceiveHeader(headers.contentSecurityPolicyReportOnly(), ContentSecur ityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
157 }
158
159 void ContentSecurityPolicy::didReceiveHeader(const String& header, ContentSecuri tyPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
160 {
161 addPolicyFromHeaderValue(header, type, source);
162 }
163
164 void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, Conte ntSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
165 {
166 Document* document = this->document();
167 if (document) {
168 UseCounter::count(*document, getUseCounterType(type));
169
170 // CSP 1.1 defines report-only in a <meta> element as invalid. Measure f or now, disable in experimental mode.
171 if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSe curityPolicyHeaderTypeReport) {
172 UseCounter::count(*document, UseCounter::ContentSecurityPolicyReport OnlyInMeta);
173 if (experimentalFeaturesEnabled()) {
174 reportReportOnlyInMeta(header);
175 return;
176 }
177 }
178 }
179
180
181 Vector<UChar> characters;
182 header.appendTo(characters);
183
184 const UChar* begin = characters.data();
185 const UChar* end = begin + characters.size();
186
187 // RFC2616, section 4.2 specifies that headers appearing multiple times can
188 // be combined with a comma. Walk the header string, and parse each comma
189 // separated chunk as a separate header.
190 const UChar* position = begin;
191 while (position < end) {
192 skipUntil<UChar>(position, end, ',');
193
194 // header1,header2 OR header1
195 // ^ ^
196 OwnPtr<CSPDirectiveList> policy = CSPDirectiveList::create(this, begin, position, type, source);
197
198 // We disable 'eval()' even in the case of report-only policies, and rel y on the check in the V8Initializer::codeGenerationCheckCallbackInMainThread cal lback to determine whether the call should execute or not.
199 if (!policy->allowEval(0, SuppressReport))
200 m_client->disableEval(policy->evalDisabledErrorMessage());
201
202 m_policies.append(policy.release());
203
204 // Skip the comma, and begin the next header from the current position.
205 ASSERT(position == end || *position == ',');
206 skipExactly<UChar>(position, end, ',');
207 begin = position;
208 }
209
210 if (document && type != ContentSecurityPolicyHeaderTypeReport && didSetRefer rerPolicy())
211 document->setReferrerPolicy(referrerPolicy());
212 }
213
214 void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value)
215 {
216 m_overrideInlineStyleAllowed = value;
217 }
218
219 const String& ContentSecurityPolicy::deprecatedHeader() const
220 {
221 return m_policies.isEmpty() ? emptyString() : m_policies[0]->header();
222 }
223
224 ContentSecurityPolicyHeaderType ContentSecurityPolicy::deprecatedHeaderType() co nst
225 {
226 return m_policies.isEmpty() ? ContentSecurityPolicyHeaderTypeEnforce : m_pol icies[0]->headerType();
227 }
228
229 template<bool (CSPDirectiveList::*allowed)(ContentSecurityPolicy::ReportingStatu s) const>
230 bool isAllowedByAll(const CSPDirectiveListVector& policies, ContentSecurityPolic y::ReportingStatus reportingStatus)
231 {
232 for (size_t i = 0; i < policies.size(); ++i) {
233 if (!(policies[i].get()->*allowed)(reportingStatus))
234 return false;
235 }
236 return true;
237 }
238
239 template<bool (CSPDirectiveList::*allowed)(ScriptState* state, ContentSecurityPo licy::ReportingStatus) const>
240 bool isAllowedByAllWithState(const CSPDirectiveListVector& policies, ScriptState * state, ContentSecurityPolicy::ReportingStatus reportingStatus)
241 {
242 for (size_t i = 0; i < policies.size(); ++i) {
243 if (!(policies[i].get()->*allowed)(state, reportingStatus))
244 return false;
245 }
246 return true;
247 }
248
249 template<bool (CSPDirectiveList::*allowed)(const String&, const WTF::OrdinalNumb er&, ContentSecurityPolicy::ReportingStatus) const>
250 bool isAllowedByAllWithContext(const CSPDirectiveListVector& policies, const Str ing& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::R eportingStatus reportingStatus)
251 {
252 for (size_t i = 0; i < policies.size(); ++i) {
253 if (!(policies[i].get()->*allowed)(contextURL, contextLine, reportingSta tus))
254 return false;
255 }
256 return true;
257 }
258
259 template<bool (CSPDirectiveList::*allowed)(const String&) const>
260 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const Strin g& nonce)
261 {
262 for (size_t i = 0; i < policies.size(); ++i) {
263 if (!(policies[i].get()->*allowed)(nonce))
264 return false;
265 }
266 return true;
267 }
268
269 template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
270 bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const CSPHas hValue& hashValue)
271 {
272 for (size_t i = 0; i < policies.size(); ++i) {
273 if (!(policies[i].get()->*allowed)(hashValue))
274 return false;
275 }
276 return true;
277 }
278
279 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPoli cy::ReportingStatus) const>
280 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& u rl, ContentSecurityPolicy::ReportingStatus reportingStatus)
281 {
282 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
283 return true;
284
285 for (size_t i = 0; i < policies.size(); ++i) {
286 if (!(policies[i].get()->*allowFromURL)(url, reportingStatus))
287 return false;
288 }
289 return true;
290 }
291
292 template<bool (CSPDirectiveList::*allowed)(LocalFrame*, ContentSecurityPolicy::R eportingStatus) const>
293 bool isAllowedByAllWithFrame(const CSPDirectiveListVector& policies, LocalFrame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus)
294 {
295 for (size_t i = 0; i < policies.size(); ++i) {
296 if (!(policies[i].get()->*allowed)(frame, reportingStatus))
297 return false;
298 }
299 return true;
300 }
301
302 void computeDigest(const CString& source, blink::WebCryptoAlgorithmId algorithmI d, DigestValue& digest)
303 {
304 blink::WebCrypto* crypto = blink::Platform::current()->crypto();
305 blink::WebArrayBuffer result;
306
307 ASSERT(crypto);
308
309 crypto->digestSynchronous(algorithmId, reinterpret_cast<const unsigned char* >(source.data()), source.length(), result);
310
311 ASSERT(!result.isNull());
312
313 digest.append(reinterpret_cast<uint8_t*>(result.data()), result.byteLength() );
314 }
315
316 template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
317 bool checkDigest(const String& source, uint8_t hashAlgorithmsUsed, const CSPDire ctiveListVector& policies)
318 {
319 // Any additions or subtractions from this struct should also modify the
320 // respective entries in the kSupportedPrefixes array in
321 // CSPSourceList::parseHash().
322 static const struct {
323 ContentSecurityPolicyHashAlgorithm cspHashAlgorithm;
324 blink::WebCryptoAlgorithmId webCryptoAlgorithmId;
325 } kAlgorithmMap[] = {
326 { ContentSecurityPolicyHashAlgorithmSha1, blink::WebCryptoAlgorithmIdSha 1 },
327 { ContentSecurityPolicyHashAlgorithmSha256, blink::WebCryptoAlgorithmIdS ha256 },
328 { ContentSecurityPolicyHashAlgorithmSha384, blink::WebCryptoAlgorithmIdS ha384 },
329 { ContentSecurityPolicyHashAlgorithmSha512, blink::WebCryptoAlgorithmIdS ha512 }
330 };
331
332 CString normalizedSource = UTF8Encoding().normalizeAndEncode(source, WTF::En titiesForUnencodables);
333
334 // See comment in CSPSourceList::parseHash about why we are using this sizeo f
335 // calculation instead of WTF_ARRAY_LENGTH.
336 for (size_t i = 0; i < (sizeof(kAlgorithmMap) / sizeof(kAlgorithmMap[0])); i ++) {
337 DigestValue digest;
338 if (kAlgorithmMap[i].cspHashAlgorithm & hashAlgorithmsUsed) {
339 computeDigest(normalizedSource, kAlgorithmMap[i].webCryptoAlgorithmI d, digest);
340 if (isAllowedByAllWithHash<allowed>(policies, CSPHashValue(kAlgorith mMap[i].cspHashAlgorithm, digest)))
341 return true;
342 }
343 }
344
345 return false;
346 }
347
348 bool ContentSecurityPolicy::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportin gStatus) const
349 {
350 return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(m_p olicies, contextURL, contextLine, reportingStatus);
351 }
352
353 bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, c onst WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus rep ortingStatus) const
354 {
355 return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineEventHandlers >(m_policies, contextURL, contextLine, reportingStatus);
356 }
357
358 bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WT F::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingS tatus) const
359 {
360 return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineScript>(m_pol icies, contextURL, contextLine, reportingStatus);
361 }
362
363 bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF ::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingSt atus) const
364 {
365 if (m_overrideInlineStyleAllowed)
366 return true;
367 return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineStyle>(m_poli cies, contextURL, contextLine, reportingStatus);
368 }
369
370 bool ContentSecurityPolicy::allowEval(ScriptState* state, ContentSecurityPolicy: :ReportingStatus reportingStatus) const
371 {
372 return isAllowedByAllWithState<&CSPDirectiveList::allowEval>(m_policies, sta te, reportingStatus);
373 }
374
375 String ContentSecurityPolicy::evalDisabledErrorMessage() const
376 {
377 for (size_t i = 0; i < m_policies.size(); ++i) {
378 if (!m_policies[i]->allowEval(0, SuppressReport))
379 return m_policies[i]->evalDisabledErrorMessage();
380 }
381 return String();
382 }
383
384 bool ContentSecurityPolicy::allowPluginType(const String& type, const String& ty peAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingSt atus) const
385 {
386 for (size_t i = 0; i < m_policies.size(); ++i) {
387 if (!m_policies[i]->allowPluginType(type, typeAttribute, url, reportingS tatus))
388 return false;
389 }
390 return true;
391 }
392
393 bool ContentSecurityPolicy::allowScriptFromSource(const KURL& url, ContentSecuri tyPolicy::ReportingStatus reportingStatus) const
394 {
395 return isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_pol icies, url, reportingStatus);
396 }
397
398 bool ContentSecurityPolicy::allowScriptNonce(const String& nonce) const
399 {
400 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_polici es, nonce);
401 }
402
403 bool ContentSecurityPolicy::allowStyleNonce(const String& nonce) const
404 {
405 return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policie s, nonce);
406 }
407
408 bool ContentSecurityPolicy::allowScriptHash(const String& source) const
409 {
410 return checkDigest<&CSPDirectiveList::allowScriptHash>(source, m_scriptHashA lgorithmsUsed, m_policies);
411 }
412
413 bool ContentSecurityPolicy::allowStyleHash(const String& source) const
414 {
415 return checkDigest<&CSPDirectiveList::allowStyleHash>(source, m_styleHashAlg orithmsUsed, m_policies);
416 }
417
418 void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms)
419 {
420 m_scriptHashAlgorithmsUsed |= algorithms;
421 }
422
423 void ContentSecurityPolicy::usesStyleHashAlgorithms(uint8_t algorithms)
424 {
425 m_styleHashAlgorithmsUsed |= algorithms;
426 }
427
428 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecuri tyPolicy::ReportingStatus reportingStatus) const
429 {
430 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_pol icies, url, reportingStatus);
431 }
432
433 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSe curityPolicy::ReportingStatus reportingStatus) const
434 {
435 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m _policies, url, reportingStatus);
436 }
437
438 bool ContentSecurityPolicy::allowImageFromSource(const KURL& url, ContentSecurit yPolicy::ReportingStatus reportingStatus) const
439 {
440 return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(m_poli cies, url, reportingStatus);
441 }
442
443 bool ContentSecurityPolicy::allowStyleFromSource(const KURL& url, ContentSecurit yPolicy::ReportingStatus reportingStatus) const
444 {
445 return isAllowedByAllWithURL<&CSPDirectiveList::allowStyleFromSource>(m_poli cies, url, reportingStatus);
446 }
447
448 bool ContentSecurityPolicy::allowFontFromSource(const KURL& url, ContentSecurity Policy::ReportingStatus reportingStatus) const
449 {
450 return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(m_polic ies, url, reportingStatus);
451 }
452
453 bool ContentSecurityPolicy::allowMediaFromSource(const KURL& url, ContentSecurit yPolicy::ReportingStatus reportingStatus) const
454 {
455 return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(m_poli cies, url, reportingStatus);
456 }
457
458 bool ContentSecurityPolicy::allowConnectToSource(const KURL& url, ContentSecurit yPolicy::ReportingStatus reportingStatus) const
459 {
460 return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(m_poli cies, url, reportingStatus);
461 }
462
463 bool ContentSecurityPolicy::allowFormAction(const KURL& url, ContentSecurityPoli cy::ReportingStatus reportingStatus) const
464 {
465 return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(m_policies, url, reportingStatus);
466 }
467
468 bool ContentSecurityPolicy::allowBaseURI(const KURL& url, ContentSecurityPolicy: :ReportingStatus reportingStatus) const
469 {
470 return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(m_policies, ur l, reportingStatus);
471 }
472
473 bool ContentSecurityPolicy::allowAncestors(LocalFrame* frame, ContentSecurityPol icy::ReportingStatus reportingStatus) const
474 {
475 return isAllowedByAllWithFrame<&CSPDirectiveList::allowAncestors>(m_policies , frame, reportingStatus);
476 }
477
478 bool ContentSecurityPolicy::allowChildContextFromSource(const KURL& url, Content SecurityPolicy::ReportingStatus reportingStatus) const
479 {
480 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource> (m_policies, url, reportingStatus);
481 }
482
483 bool ContentSecurityPolicy::allowWorkerContextFromSource(const KURL& url, Conten tSecurityPolicy::ReportingStatus reportingStatus) const
484 {
485 // CSP 1.1 moves workers from 'script-src' to the new 'child-src'. Measure t he impact of this backwards-incompatible change.
486 if (m_client->isDocument()) {
487 Document* document = static_cast<Document*>(m_client);
488 UseCounter::count(*document, UseCounter::WorkerSubjectToCSP);
489 if (isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource >(m_policies, url, SuppressReport) && !isAllowedByAllWithURL<&CSPDirectiveList:: allowScriptFromSource>(m_policies, url, SuppressReport))
490 UseCounter::count(*document, UseCounter::WorkerAllowedByChildBlocked ByScript);
491 }
492
493 return experimentalFeaturesEnabled() ?
494 isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_ policies, url, reportingStatus) :
495 isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_polici es, url, reportingStatus);
496 }
497
498 bool ContentSecurityPolicy::isActive() const
499 {
500 return !m_policies.isEmpty();
501 }
502
503 ReflectedXSSDisposition ContentSecurityPolicy::reflectedXSSDisposition() const
504 {
505 ReflectedXSSDisposition disposition = ReflectedXSSUnset;
506 for (size_t i = 0; i < m_policies.size(); ++i) {
507 if (m_policies[i]->reflectedXSSDisposition() > disposition)
508 disposition = std::max(disposition, m_policies[i]->reflectedXSSDispo sition());
509 }
510 return disposition;
511 }
512
513 ReferrerPolicy ContentSecurityPolicy::referrerPolicy() const
514 {
515 ReferrerPolicy policy = ReferrerPolicyDefault;
516 bool first = true;
517 for (size_t i = 0; i < m_policies.size(); ++i) {
518 if (m_policies[i]->didSetReferrerPolicy()) {
519 if (first)
520 policy = m_policies[i]->referrerPolicy();
521 else
522 policy = mergeReferrerPolicies(policy, m_policies[i]->referrerPo licy());
523 }
524 }
525 return policy;
526 }
527
528 bool ContentSecurityPolicy::didSetReferrerPolicy() const
529 {
530 for (size_t i = 0; i < m_policies.size(); ++i) {
531 if (m_policies[i]->didSetReferrerPolicy())
532 return true;
533 }
534 return false;
535 }
536
537 SecurityOrigin* ContentSecurityPolicy::securityOrigin() const
538 {
539 return m_client->securityContext().securityOrigin();
540 }
541
542 const KURL ContentSecurityPolicy::url() const
543 {
544 return m_client->contextURL();
545 }
546
547 KURL ContentSecurityPolicy::completeURL(const String& url) const
548 {
549 return m_client->contextCompleteURL(url);
550 }
551
552 void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask) const
553 {
554 if (Document* document = this->document())
555 document->enforceSandboxFlags(mask);
556 }
557
558 static String stripURLForUseInReport(Document* document, const KURL& url)
559 {
560 if (!url.isValid())
561 return String();
562 if (!url.isHierarchical() || url.protocolIs("file"))
563 return url.protocol();
564 return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsRef errer() : SecurityOrigin::create(url)->toString();
565 }
566
567 static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventI nit& init, Document* document, const String& directiveText, const String& effect iveDirective, const KURL& blockedURL, const String& header)
568 {
569 init.documentURI = document->url().string();
570 init.referrer = document->referrer();
571 init.blockedURI = stripURLForUseInReport(document, blockedURL);
572 init.violatedDirective = directiveText;
573 init.effectiveDirective = effectiveDirective;
574 init.originalPolicy = header;
575 init.sourceFile = String();
576 init.lineNumber = 0;
577 init.columnNumber = 0;
578 init.statusCode = 0;
579
580 if (!SecurityOrigin::isSecure(document->url()) && document->loader())
581 init.statusCode = document->loader()->response().httpStatusCode();
582
583 RefPtr<ScriptCallStack> stack = createScriptCallStack(1, false);
584 if (!stack)
585 return;
586
587 const ScriptCallFrame& callFrame = stack->at(0);
588
589 if (callFrame.lineNumber()) {
590 KURL source = KURL(ParsedURLString, callFrame.sourceURL());
591 init.sourceFile = stripURLForUseInReport(document, source);
592 init.lineNumber = callFrame.lineNumber();
593 init.columnNumber = callFrame.columnNumber();
594 }
595 }
596
597 void ContentSecurityPolicy::reportViolation(const String& directiveText, const S tring& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header)
598 {
599 // FIXME: Support sending reports from worker.
600 if (!m_client->isDocument())
601 return;
602
603 Document* document = this->document();
604 LocalFrame* frame = document->frame();
605 if (!frame)
606 return;
607
608 SecurityPolicyViolationEventInit violationData;
609 gatherSecurityPolicyViolationEventData(violationData, document, directiveTex t, effectiveDirective, blockedURL, header);
610
611 if (experimentalFeaturesEnabled())
612 frame->domWindow()->enqueueDocumentEvent(SecurityPolicyViolationEvent::c reate(EventTypeNames::securitypolicyviolation, violationData));
613
614 if (reportURIs.isEmpty())
615 return;
616
617 // We need to be careful here when deciding what information to send to the
618 // report-uri. Currently, we send only the current document's URL and the
619 // directive that was violated. The document's URL is safe to send because
620 // it's the document itself that's requesting that it be sent. You could
621 // make an argument that we shouldn't send HTTPS document URLs to HTTP
622 // report-uris (for the same reasons that we supress the Referer in that
623 // case), but the Referer is sent implicitly whereas this request is only
624 // sent explicitly. As for which directive was violated, that's pretty
625 // harmless information.
626
627 RefPtr<JSONObject> cspReport = JSONObject::create();
628 cspReport->setString("document-uri", violationData.documentURI);
629 cspReport->setString("referrer", violationData.referrer);
630 cspReport->setString("violated-directive", violationData.violatedDirective);
631 if (experimentalFeaturesEnabled())
632 cspReport->setString("effective-directive", violationData.effectiveDirec tive);
633 cspReport->setString("original-policy", violationData.originalPolicy);
634 cspReport->setString("blocked-uri", violationData.blockedURI);
635 if (!violationData.sourceFile.isEmpty() && violationData.lineNumber) {
636 cspReport->setString("source-file", violationData.sourceFile);
637 cspReport->setNumber("line-number", violationData.lineNumber);
638 cspReport->setNumber("column-number", violationData.columnNumber);
639 }
640 cspReport->setNumber("status-code", violationData.statusCode);
641
642 RefPtr<JSONObject> reportObject = JSONObject::create();
643 reportObject->setObject("csp-report", cspReport.release());
644 String stringifiedReport = reportObject->toJSONString();
645
646 if (!shouldSendViolationReport(stringifiedReport))
647 return;
648
649 RefPtr<FormData> report = FormData::create(stringifiedReport.utf8());
650
651 for (size_t i = 0; i < reportURIs.size(); ++i)
652 PingLoader::sendViolationReport(frame, reportURIs[i], report, PingLoader ::ContentSecurityPolicyViolationReport);
653
654 didSendViolationReport(stringifiedReport);
655 }
656
657 void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue) co nst
658 {
659 logToConsole("The 'referrer' Content Security Policy directive has the inval id value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"n ever\", and \"origin\".");
660 }
661
662 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) const
663 {
664 logToConsole("The report-only Content Security Policy '" + header + "' was d elivered via a <meta> element, which is disallowed. The policy has been ignored. ");
665 }
666
667 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) const
668 {
669 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.");
670 }
671
672 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) const
673 {
674 logToConsole("The Content Security Policy directive '" + name + "' is ignore d when delivered in a report-only policy.");
675 }
676
677 void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const
678 {
679 DEFINE_STATIC_LOCAL(String, allow, ("allow"));
680 DEFINE_STATIC_LOCAL(String, options, ("options"));
681 DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri"));
682 DEFINE_STATIC_LOCAL(String, allowMessage, ("The 'allow' directive has been r eplaced with 'default-src'. Please use that directive instead, as 'allow' has no effect."));
683 DEFINE_STATIC_LOCAL(String, optionsMessage, ("The 'options' directive has be en replaced with 'unsafe-inline' and 'unsafe-eval' source expressions for the 's cript-src' and 'style-src' directives. Please use those directives instead, as ' options' has no effect."));
684 DEFINE_STATIC_LOCAL(String, policyURIMessage, ("The 'policy-uri' directive h as been removed from the specification. Please specify a complete policy via the Content-Security-Policy header."));
685
686 String message = "Unrecognized Content-Security-Policy directive '" + name + "'.\n";
687 if (equalIgnoringCase(name, allow))
688 message = allowMessage;
689 else if (equalIgnoringCase(name, options))
690 message = optionsMessage;
691 else if (equalIgnoringCase(name, policyURI))
692 message = policyURIMessage;
693
694 logToConsole(message);
695 }
696
697 void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& dire ctiveName, const String& sourceExpression) const
698 {
699 String message = "The Content Security Policy directive '" + directiveName + "' contains '" + sourceExpression + "' as a source expression. Did you mean '" + directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?";
700 logToConsole(message);
701 }
702
703 void ContentSecurityPolicy::reportDuplicateDirective(const String& name) const
704 {
705 String message = "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n";
706 logToConsole(message);
707 }
708
709 void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) c onst
710 {
711 String message;
712 if (pluginType.isNull())
713 message = "'plugin-types' Content Security Policy directive is empty; al l plugins will be blocked.\n";
714 else
715 message = "Invalid plugin type in 'plugin-types' Content Security Policy directive: '" + pluginType + "'.\n";
716 logToConsole(message);
717 }
718
719 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags ) const
720 {
721 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire ctive: " + invalidFlags);
722 }
723
724 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue ) const
725 {
726 logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\", and \"block\".");
727 }
728
729 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d irectiveName, const String& value) const
730 {
731 String message = "The value for Content Security Policy directive '" + direc tiveName + "' contains an invalid character: '" + value + "'. Non-whitespace cha racters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 398 6, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.";
732 logToConsole(message);
733 }
734
735 void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveNa me, const String& value, const char invalidChar) const
736 {
737 ASSERT(invalidChar == '#' || invalidChar == '?');
738
739 String ignoring = "The fragment identifier, including the '#', will be ignor ed.";
740 if (invalidChar == '?')
741 ignoring = "The query component, including the '?', will be ignored.";
742 String message = "The source list for Content Security Policy directive '" + directiveName + "' contains a source with an invalid path: '" + value + "'. " + ignoring;
743 logToConsole(message);
744 }
745
746 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv eName, const String& source) const
747 {
748 String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ign ored.";
749 if (equalIgnoringCase(source, "'none'"))
750 message = message + " Note that 'none' has no effect unless it is the on ly expression in the source list.";
751 logToConsole(message);
752 }
753
754 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const
755 {
756 logToConsole("The Content Security Policy '" + policy + "' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no e ffect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header.");
757 }
758
759 void ContentSecurityPolicy::logToConsole(const String& message) const
760 {
761 m_client->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, messag e);
762 }
763
764 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String & directiveText) const
765 {
766 m_client->reportBlockedScriptExecutionToInspector(directiveText);
767 }
768
769 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const
770 {
771 return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnab led();
772 }
773
774 bool ContentSecurityPolicy::shouldBypassMainWorld(ExecutionContext* context)
775 {
776 if (context && context->isDocument()) {
777 Document* document = toDocument(context);
778 if (document->frame())
779 return document->frame()->script().shouldBypassMainWorldContentSecur ityPolicy();
780 }
781 return false;
782 }
783
784 bool ContentSecurityPolicy::shouldSendViolationReport(const String& report) cons t
785 {
786 // Collisions have no security impact, so we can save space by storing only the string's hash rather than the whole report.
787 return !m_violationReportsSent.contains(report.impl()->hash());
788 }
789
790 void ContentSecurityPolicy::didSendViolationReport(const String& report)
791 {
792 m_violationReportsSent.add(report.impl()->hash());
793 }
794
795 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/frame/ContentSecurityPolicy.h ('k') | Source/core/frame/csp/CSPDirectiveList.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698