OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google, Inc. All rights reserved. | 2 * Copyright (C) 2011 Google, Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 , m_sandboxMask(0) | 139 , m_sandboxMask(0) |
140 , m_referrerPolicy(ReferrerPolicyDefault) | 140 , m_referrerPolicy(ReferrerPolicyDefault) |
141 { | 141 { |
142 } | 142 } |
143 | 143 |
144 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() | 144 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() |
145 { | 145 { |
146 // Ensure that 'self' processes correctly. | 146 // Ensure that 'self' processes correctly. |
147 m_selfSource = adoptPtr(new CSPSource(this, securityOrigin()->protocol(), se
curityOrigin()->host(), securityOrigin()->port(), String(), false, false)); | 147 m_selfSource = adoptPtr(new CSPSource(this, securityOrigin()->protocol(), se
curityOrigin()->host(), securityOrigin()->port(), String(), false, false)); |
148 | 148 |
149 // If we're in a Document, set the referrer policy and sandbox flags. | 149 // If we're in a Document, set the referrer policy and sandbox flags, then d
ump all the |
| 150 // parsing error messages, then poke at histograms. |
150 if (Document* document = this->document()) { | 151 if (Document* document = this->document()) { |
151 document->enforceSandboxFlags(m_sandboxMask); | 152 document->enforceSandboxFlags(m_sandboxMask); |
152 if (didSetReferrerPolicy()) | 153 if (didSetReferrerPolicy()) |
153 document->setReferrerPolicy(m_referrerPolicy); | 154 document->setReferrerPolicy(m_referrerPolicy); |
| 155 |
| 156 for (ConsoleMessageVector::const_iterator iter = m_consoleMessages.begin
(); iter != m_consoleMessages.end(); ++iter) |
| 157 executionContext()->addConsoleMessage(*iter); |
| 158 m_consoleMessages.clear(); |
| 159 |
| 160 for (CSPDirectiveListVector::const_iterator iter = m_policies.begin(); i
ter != m_policies.end(); ++iter) |
| 161 UseCounter::count(*document, getUseCounterType((*iter)->headerType()
)); |
154 } | 162 } |
155 | 163 |
156 // We disable 'eval()' even in the case of report-only policies, and rely on
the check in the | 164 // We disable 'eval()' even in the case of report-only policies, and rely on
the check in the |
157 // V8Initializer::codeGenerationCheckCallbackInMainThread callback to determ
ine whether the | 165 // V8Initializer::codeGenerationCheckCallbackInMainThread callback to determ
ine whether the |
158 // call should execute or not. | 166 // call should execute or not. |
159 if (!m_disableEvalErrorMessage.isNull()) | 167 if (!m_disableEvalErrorMessage.isNull()) |
160 executionContext()->disableEval(m_disableEvalErrorMessage); | 168 executionContext()->disableEval(m_disableEvalErrorMessage); |
161 } | 169 } |
162 | 170 |
163 ContentSecurityPolicy::~ContentSecurityPolicy() | 171 ContentSecurityPolicy::~ContentSecurityPolicy() |
(...skipping 30 matching lines...) Expand all Loading... |
194 { | 202 { |
195 addPolicyFromHeaderValue(header, type, source); | 203 addPolicyFromHeaderValue(header, type, source); |
196 | 204 |
197 // FIXME: This ought to be a step distinct from didReceiveHeader(). https://
crbug.com/411889 | 205 // FIXME: This ought to be a step distinct from didReceiveHeader(). https://
crbug.com/411889 |
198 if (sideEffectDisposition == ApplySideEffectsToExecutionContext) | 206 if (sideEffectDisposition == ApplySideEffectsToExecutionContext) |
199 applyPolicySideEffectsToExecutionContext(); | 207 applyPolicySideEffectsToExecutionContext(); |
200 } | 208 } |
201 | 209 |
202 void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, Conte
ntSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source) | 210 void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, Conte
ntSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source) |
203 { | 211 { |
204 Document* document = this->document(); | 212 if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecuri
tyPolicyHeaderTypeReport && experimentalFeaturesEnabled()) { |
205 if (document) { | 213 reportReportOnlyInMeta(header); |
206 UseCounter::count(*document, getUseCounterType(type)); | 214 return; |
207 | |
208 // CSP 1.1 defines report-only in a <meta> element as invalid. Measure f
or now, disable in experimental mode. | |
209 if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSe
curityPolicyHeaderTypeReport) { | |
210 UseCounter::count(*document, UseCounter::ContentSecurityPolicyReport
OnlyInMeta); | |
211 if (experimentalFeaturesEnabled()) { | |
212 reportReportOnlyInMeta(header); | |
213 return; | |
214 } | |
215 } | |
216 } | 215 } |
217 | 216 |
218 Vector<UChar> characters; | 217 Vector<UChar> characters; |
219 header.appendTo(characters); | 218 header.appendTo(characters); |
220 | 219 |
221 const UChar* begin = characters.data(); | 220 const UChar* begin = characters.data(); |
222 const UChar* end = begin + characters.size(); | 221 const UChar* end = begin + characters.size(); |
223 | 222 |
224 // RFC2616, section 4.2 specifies that headers appearing multiple times can | 223 // RFC2616, section 4.2 specifies that headers appearing multiple times can |
225 // be combined with a comma. Walk the header string, and parse each comma | 224 // be combined with a comma. Walk the header string, and parse each comma |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
673 return; | 672 return; |
674 | 673 |
675 RefPtr<FormData> report = FormData::create(stringifiedReport.utf8()); | 674 RefPtr<FormData> report = FormData::create(stringifiedReport.utf8()); |
676 | 675 |
677 for (size_t i = 0; i < reportURIs.size(); ++i) | 676 for (size_t i = 0; i < reportURIs.size(); ++i) |
678 PingLoader::sendViolationReport(frame, reportURIs[i], report, PingLoader
::ContentSecurityPolicyViolationReport); | 677 PingLoader::sendViolationReport(frame, reportURIs[i], report, PingLoader
::ContentSecurityPolicyViolationReport); |
679 | 678 |
680 didSendViolationReport(stringifiedReport); | 679 didSendViolationReport(stringifiedReport); |
681 } | 680 } |
682 | 681 |
683 void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue) co
nst | 682 void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue) |
684 { | 683 { |
685 logToConsole("The 'referrer' Content Security Policy directive has the inval
id value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"n
ever\", and \"origin\"."); | 684 logToConsole("The 'referrer' Content Security Policy directive has the inval
id value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"n
ever\", and \"origin\"."); |
686 } | 685 } |
687 | 686 |
688 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) const | 687 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) |
689 { | 688 { |
690 logToConsole("The report-only Content Security Policy '" + header + "' was d
elivered via a <meta> element, which is disallowed. The policy has been ignored.
"); | 689 logToConsole("The report-only Content Security Policy '" + header + "' was d
elivered via a <meta> element, which is disallowed. The policy has been ignored.
"); |
691 } | 690 } |
692 | 691 |
693 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) const | 692 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) |
694 { | 693 { |
695 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."); | 694 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."); |
696 } | 695 } |
697 | 696 |
698 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) const | 697 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) |
699 { | 698 { |
700 logToConsole("The Content Security Policy directive '" + name + "' is ignore
d when delivered in a report-only policy."); | 699 logToConsole("The Content Security Policy directive '" + name + "' is ignore
d when delivered in a report-only policy."); |
701 } | 700 } |
702 | 701 |
703 void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const | 702 void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) |
704 { | 703 { |
705 DEFINE_STATIC_LOCAL(String, allow, ("allow")); | 704 DEFINE_STATIC_LOCAL(String, allow, ("allow")); |
706 DEFINE_STATIC_LOCAL(String, options, ("options")); | 705 DEFINE_STATIC_LOCAL(String, options, ("options")); |
707 DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri")); | 706 DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri")); |
708 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.")); | 707 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.")); |
709 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.")); | 708 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.")); |
710 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.")); | 709 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.")); |
711 | 710 |
712 String message = "Unrecognized Content-Security-Policy directive '" + name +
"'.\n"; | 711 String message = "Unrecognized Content-Security-Policy directive '" + name +
"'.\n"; |
713 MessageLevel level = ErrorMessageLevel; | 712 MessageLevel level = ErrorMessageLevel; |
714 if (equalIgnoringCase(name, allow)) { | 713 if (equalIgnoringCase(name, allow)) { |
715 message = allowMessage; | 714 message = allowMessage; |
716 } else if (equalIgnoringCase(name, options)) { | 715 } else if (equalIgnoringCase(name, options)) { |
717 message = optionsMessage; | 716 message = optionsMessage; |
718 } else if (equalIgnoringCase(name, policyURI)) { | 717 } else if (equalIgnoringCase(name, policyURI)) { |
719 message = policyURIMessage; | 718 message = policyURIMessage; |
720 } else if (isDirectiveName(name)) { | 719 } else if (isDirectiveName(name)) { |
721 message = "The Content-Security-Policy directive '" + name + "' is imple
mented behind a flag which is currently disabled.\n"; | 720 message = "The Content-Security-Policy directive '" + name + "' is imple
mented behind a flag which is currently disabled.\n"; |
722 level = InfoMessageLevel; | 721 level = InfoMessageLevel; |
723 } | 722 } |
724 | 723 |
725 logToConsole(message, level); | 724 logToConsole(message, level); |
726 } | 725 } |
727 | 726 |
728 void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& dire
ctiveName, const String& sourceExpression) const | 727 void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& dire
ctiveName, const String& sourceExpression) |
729 { | 728 { |
730 String message = "The Content Security Policy directive '" + directiveName +
"' contains '" + sourceExpression + "' as a source expression. Did you mean '"
+ directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?"; | 729 String message = "The Content Security Policy directive '" + directiveName +
"' contains '" + sourceExpression + "' as a source expression. Did you mean '"
+ directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?"; |
731 logToConsole(message); | 730 logToConsole(message); |
732 } | 731 } |
733 | 732 |
734 void ContentSecurityPolicy::reportDuplicateDirective(const String& name) const | 733 void ContentSecurityPolicy::reportDuplicateDirective(const String& name) |
735 { | 734 { |
736 String message = "Ignoring duplicate Content-Security-Policy directive '" +
name + "'.\n"; | 735 String message = "Ignoring duplicate Content-Security-Policy directive '" +
name + "'.\n"; |
737 logToConsole(message); | 736 logToConsole(message); |
738 } | 737 } |
739 | 738 |
740 void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) c
onst | 739 void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) |
741 { | 740 { |
742 String message; | 741 String message; |
743 if (pluginType.isNull()) | 742 if (pluginType.isNull()) |
744 message = "'plugin-types' Content Security Policy directive is empty; al
l plugins will be blocked.\n"; | 743 message = "'plugin-types' Content Security Policy directive is empty; al
l plugins will be blocked.\n"; |
745 else | 744 else |
746 message = "Invalid plugin type in 'plugin-types' Content Security Policy
directive: '" + pluginType + "'.\n"; | 745 message = "Invalid plugin type in 'plugin-types' Content Security Policy
directive: '" + pluginType + "'.\n"; |
747 logToConsole(message); | 746 logToConsole(message); |
748 } | 747 } |
749 | 748 |
750 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags
) const | 749 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags
) |
751 { | 750 { |
752 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire
ctive: " + invalidFlags); | 751 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire
ctive: " + invalidFlags); |
753 } | 752 } |
754 | 753 |
755 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue
) const | 754 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue
) |
756 { | 755 { |
757 logToConsole("The 'reflected-xss' Content Security Policy directive has the
invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\",
and \"block\"."); | 756 logToConsole("The 'reflected-xss' Content Security Policy directive has the
invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\",
and \"block\"."); |
758 } | 757 } |
759 | 758 |
760 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d
irectiveName, const String& value) const | 759 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d
irectiveName, const String& value) |
761 { | 760 { |
762 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."; | 761 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."; |
763 logToConsole(message); | 762 logToConsole(message); |
764 } | 763 } |
765 | 764 |
766 void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveNa
me, const String& value, const char invalidChar) const | 765 void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveNa
me, const String& value, const char invalidChar) |
767 { | 766 { |
768 ASSERT(invalidChar == '#' || invalidChar == '?'); | 767 ASSERT(invalidChar == '#' || invalidChar == '?'); |
769 | 768 |
770 String ignoring = "The fragment identifier, including the '#', will be ignor
ed."; | 769 String ignoring = "The fragment identifier, including the '#', will be ignor
ed."; |
771 if (invalidChar == '?') | 770 if (invalidChar == '?') |
772 ignoring = "The query component, including the '?', will be ignored."; | 771 ignoring = "The query component, including the '?', will be ignored."; |
773 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains a source with an invalid path: '" + value + "'. " +
ignoring; | 772 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains a source with an invalid path: '" + value + "'. " +
ignoring; |
774 logToConsole(message); | 773 logToConsole(message); |
775 } | 774 } |
776 | 775 |
777 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv
eName, const String& source) const | 776 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv
eName, const String& source) |
778 { | 777 { |
779 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains an invalid source: '" + source + "'. It will be ign
ored."; | 778 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains an invalid source: '" + source + "'. It will be ign
ored."; |
780 if (equalIgnoringCase(source, "'none'")) | 779 if (equalIgnoringCase(source, "'none'")) |
781 message = message + " Note that 'none' has no effect unless it is the on
ly expression in the source list."; | 780 message = message + " Note that 'none' has no effect unless it is the on
ly expression in the source list."; |
782 logToConsole(message); | 781 logToConsole(message); |
783 } | 782 } |
784 | 783 |
785 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const | 784 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) |
786 { | 785 { |
787 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."); | 786 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."); |
788 } | 787 } |
789 | 788 |
790 void ContentSecurityPolicy::logToConsole(const String& message, MessageLevel lev
el) const | 789 void ContentSecurityPolicy::logToConsole(const String& message, MessageLevel lev
el) |
791 { | 790 { |
792 m_executionContext->addConsoleMessage(ConsoleMessage::create(SecurityMessage
Source, level, message)); | 791 logToConsole(ConsoleMessage::create(SecurityMessageSource, level, message)); |
| 792 } |
| 793 |
| 794 void ContentSecurityPolicy::logToConsole(PassRefPtr<ConsoleMessage> consoleMessa
ge) |
| 795 { |
| 796 if (m_executionContext) |
| 797 m_executionContext->addConsoleMessage(consoleMessage); |
| 798 else |
| 799 m_consoleMessages.append(consoleMessage); |
793 } | 800 } |
794 | 801 |
795 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String
& directiveText) const | 802 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String
& directiveText) const |
796 { | 803 { |
797 m_executionContext->reportBlockedScriptExecutionToInspector(directiveText); | 804 m_executionContext->reportBlockedScriptExecutionToInspector(directiveText); |
798 } | 805 } |
799 | 806 |
800 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const | 807 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const |
801 { | 808 { |
802 return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnab
led(); | 809 return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnab
led(); |
(...skipping 27 matching lines...) Expand all Loading... |
830 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. | 837 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. |
831 return !m_violationReportsSent.contains(report.impl()->hash()); | 838 return !m_violationReportsSent.contains(report.impl()->hash()); |
832 } | 839 } |
833 | 840 |
834 void ContentSecurityPolicy::didSendViolationReport(const String& report) | 841 void ContentSecurityPolicy::didSendViolationReport(const String& report) |
835 { | 842 { |
836 m_violationReportsSent.add(report.impl()->hash()); | 843 m_violationReportsSent.add(report.impl()->hash()); |
837 } | 844 } |
838 | 845 |
839 } // namespace blink | 846 } // namespace blink |
OLD | NEW |