| 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 |