diff options
Diffstat (limited to 'extensions/common')
-rw-r--r-- | extensions/common/csp_validator.cc | 184 | ||||
-rw-r--r-- | extensions/common/csp_validator.h | 9 | ||||
-rw-r--r-- | extensions/common/csp_validator_unittest.cc | 525 | ||||
-rw-r--r-- | extensions/common/manifest_constants.cc | 17 | ||||
-rw-r--r-- | extensions/common/manifest_constants.h | 2 | ||||
-rw-r--r-- | extensions/common/manifest_handlers/csp_info.cc | 36 |
6 files changed, 496 insertions, 277 deletions
diff --git a/extensions/common/csp_validator.cc b/extensions/common/csp_validator.cc index 6895b31..371d7f8 100644 --- a/extensions/common/csp_validator.cc +++ b/extensions/common/csp_validator.cc @@ -11,6 +11,9 @@ #include "base/strings/string_util.h" #include "content/public/common/url_constants.h" #include "extensions/common/constants.h" +#include "extensions/common/error_utils.h" +#include "extensions/common/install_warning.h" +#include "extensions/common/manifest_constants.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" namespace extensions { @@ -24,6 +27,10 @@ const char kScriptSrc[] = "script-src"; const char kObjectSrc[] = "object-src"; const char kPluginTypes[] = "plugin-types"; +const char kObjectSrcDefaultDirective[] = "object-src 'self';"; +const char kScriptSrcDefaultDirective[] = + "script-src 'self' chrome-extension-resource:;"; + const char kSandboxDirectiveName[] = "sandbox"; const char kAllowSameOriginToken[] = "allow-same-origin"; const char kAllowTopNavigation[] = "allow-top-navigation"; @@ -38,14 +45,10 @@ const char* const kSandboxedPluginTypes[] = { struct DirectiveStatus { explicit DirectiveStatus(const char* name) - : directive_name(name) - , seen_in_policy(false) - , is_secure(false) { - } + : directive_name(name), seen_in_policy(false) {} const char* directive_name; bool seen_in_policy; - bool is_secure; }; // Returns whether |url| starts with |scheme_and_separator| and does not have a @@ -63,12 +66,6 @@ bool isNonWildcardTLD(const std::string& url, if (end_of_host == std::string::npos) end_of_host = url.size(); - // A missing host such as "chrome-extension://" is invalid, but for backwards- - // compatibility, accept such CSP parts. They will be ignored by Blink anyway. - // TODO(robwu): Remove this special case once crbug.com/434773 is fixed. - if (start_of_host == end_of_host) - return true; - // Note: It is sufficient to only compare the first character against '*' // because the CSP only allows wildcards at the start of a directive, see // host-source and host-part at http://www.w3.org/TR/CSP2/#source-list-syntax @@ -115,11 +112,20 @@ bool isNonWildcardTLD(const std::string& url, return registry_length != 0; } -bool HasOnlySecureTokens(base::StringTokenizer& tokenizer, - int options) { - while (tokenizer.GetNext()) { - std::string source = tokenizer.token(); +InstallWarning CSPInstallWarning(const std::string& csp_warning) { + return InstallWarning(csp_warning, manifest_keys::kContentSecurityPolicy); +} + +void GetSecureDirectiveValues(const std::string& directive_name, + base::StringTokenizer* tokenizer, + int options, + std::vector<std::string>* sane_csp_parts, + std::vector<InstallWarning>* warnings) { + sane_csp_parts->push_back(directive_name); + while (tokenizer->GetNext()) { + std::string source = tokenizer->token(); base::StringToLowerASCII(&source); + bool is_secure_csp_token = false; // We might need to relax this whitelist over time. if (source == "'self'" || @@ -137,52 +143,45 @@ bool HasOnlySecureTokens(base::StringTokenizer& tokenizer, url::kStandardSchemeSeparator, false) || StartsWithASCII(source, "chrome-extension-resource:", true)) { - continue; + is_secure_csp_token = true; + } else if ((options & OPTIONS_ALLOW_UNSAFE_EVAL) && + source == "'unsafe-eval'") { + is_secure_csp_token = true; } - if (options & OPTIONS_ALLOW_UNSAFE_EVAL) { - if (source == "'unsafe-eval'") - continue; + if (is_secure_csp_token) { + sane_csp_parts->push_back(source); + } else if (warnings) { + warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( + manifest_errors::kInvalidCSPInsecureValue, source, directive_name))); } - - return false; } - - return true; // Empty values default to 'none', which is secure. + // End of CSP directive that was started at the beginning of this method. If + // none of the values are secure, the policy will be empty and default to + // 'none', which is secure. + sane_csp_parts->back().push_back(';'); } // Returns true if |directive_name| matches |status.directive_name|. bool UpdateStatus(const std::string& directive_name, - base::StringTokenizer& tokenizer, + base::StringTokenizer* tokenizer, DirectiveStatus* status, - int options) { - if (status->seen_in_policy) - return false; + int options, + std::vector<std::string>* sane_csp_parts, + std::vector<InstallWarning>* warnings) { if (directive_name != status->directive_name) return false; - status->seen_in_policy = true; - status->is_secure = HasOnlySecureTokens(tokenizer, options); - return true; -} - -// Parses the plugin-types directive and returns the list of mime types -// specified in |plugin_types|. -bool ParsePluginTypes(const std::string& directive_name, - base::StringTokenizer& tokenizer, - std::vector<std::string>* plugin_types) { - DCHECK(plugin_types); - - if (directive_name != kPluginTypes || !plugin_types->empty()) - return false; - while (tokenizer.GetNext()) { - std::string mime_type = tokenizer.token(); - base::StringToLowerASCII(&mime_type); - // Since we're comparing the mime types to a whitelist, we don't check them - // for strict validity right now. - plugin_types->push_back(mime_type); + if (!status->seen_in_policy) { + status->seen_in_policy = true; + GetSecureDirectiveValues(directive_name, tokenizer, options, sane_csp_parts, + warnings); + } else { + // Don't show any errors for duplicate CSP directives, because it will be + // ignored by the CSP parser (http://www.w3.org/TR/CSP2/#policy-parsing). + GetSecureDirectiveValues(directive_name, tokenizer, options, sane_csp_parts, + NULL); } - return true; } @@ -201,20 +200,26 @@ bool PluginTypeAllowed(const std::string& plugin_type) { // the set specified in kSandboxedPluginTypes. bool AllowedToHaveInsecureObjectSrc( int options, - const std::vector<std::string>& plugin_types) { + const std::vector<std::string>& directives) { if (!(options & OPTIONS_ALLOW_INSECURE_OBJECT_SRC)) return false; - // plugin-types must be specified. - if (plugin_types.empty()) - return false; - - for (const auto& plugin_type : plugin_types) { - if (!PluginTypeAllowed(plugin_type)) - return false; + for (size_t i = 0; i < directives.size(); ++i) { + const std::string& input = directives[i]; + base::StringTokenizer tokenizer(input, " \t\r\n"); + if (!tokenizer.GetNext()) + continue; + if (!LowerCaseEqualsASCII(tokenizer.token(), kPluginTypes)) + continue; + while (tokenizer.GetNext()) { + if (!PluginTypeAllowed(tokenizer.token())) + return false; + } + // All listed plugin types are whitelisted. + return true; } - - return true; + // plugin-types not specified. + return false; } } // namespace @@ -228,8 +233,10 @@ bool ContentSecurityPolicyIsLegal(const std::string& policy) { std::string::npos; } -bool ContentSecurityPolicyIsSecure(const std::string& policy, - int options) { +std::string SanitizeContentSecurityPolicy( + const std::string& policy, + int options, + std::vector<InstallWarning>* warnings) { // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. std::vector<std::string> directives; base::SplitString(policy, ';', &directives); @@ -238,8 +245,11 @@ bool ContentSecurityPolicyIsSecure(const std::string& policy, DirectiveStatus script_src_status(kScriptSrc); DirectiveStatus object_src_status(kObjectSrc); - std::vector<std::string> plugin_types; + bool allow_insecure_object_src = + AllowedToHaveInsecureObjectSrc(options, directives); + std::vector<std::string> sane_csp_parts; + std::vector<InstallWarning> default_src_csp_warnings; for (size_t i = 0; i < directives.size(); ++i) { std::string& input = directives[i]; base::StringTokenizer tokenizer(input, " \t\r\n"); @@ -249,33 +259,47 @@ bool ContentSecurityPolicyIsSecure(const std::string& policy, std::string directive_name = tokenizer.token(); base::StringToLowerASCII(&directive_name); - if (UpdateStatus(directive_name, tokenizer, &default_src_status, options)) - continue; - if (UpdateStatus(directive_name, tokenizer, &script_src_status, options)) + if (UpdateStatus(directive_name, &tokenizer, &default_src_status, options, + &sane_csp_parts, &default_src_csp_warnings)) continue; - if (UpdateStatus(directive_name, tokenizer, &object_src_status, options)) + if (UpdateStatus(directive_name, &tokenizer, &script_src_status, options, + &sane_csp_parts, warnings)) continue; - if (ParsePluginTypes(directive_name, tokenizer, &plugin_types)) + if (!allow_insecure_object_src && + UpdateStatus(directive_name, &tokenizer, &object_src_status, options, + &sane_csp_parts, warnings)) continue; - } - if (script_src_status.seen_in_policy && !script_src_status.is_secure) - return false; - - if (object_src_status.seen_in_policy && !object_src_status.is_secure) { - // Note that this does not fully check the object-src source list for - // validity but Blink will do this anyway. - if (!AllowedToHaveInsecureObjectSrc(options, plugin_types)) - return false; + // Pass the other CSP directives as-is without further validation. + sane_csp_parts.push_back(input + ";"); } - if (default_src_status.seen_in_policy && !default_src_status.is_secure) { - return script_src_status.seen_in_policy && - object_src_status.seen_in_policy; + if (default_src_status.seen_in_policy) { + if (!script_src_status.seen_in_policy || + !object_src_status.seen_in_policy) { + // Insecure values in default-src are only relevant if either script-src + // or object-src is omitted. + if (warnings) + warnings->insert(warnings->end(), + default_src_csp_warnings.begin(), + default_src_csp_warnings.end()); + } + } else { + if (!script_src_status.seen_in_policy) { + sane_csp_parts.push_back(kScriptSrcDefaultDirective); + if (warnings) + warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( + manifest_errors::kInvalidCSPMissingSecureSrc, kScriptSrc))); + } + if (!object_src_status.seen_in_policy && !allow_insecure_object_src) { + sane_csp_parts.push_back(kObjectSrcDefaultDirective); + if (warnings) + warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( + manifest_errors::kInvalidCSPMissingSecureSrc, kObjectSrc))); + } } - return default_src_status.seen_in_policy || - (script_src_status.seen_in_policy && object_src_status.seen_in_policy); + return JoinString(sane_csp_parts, ' '); } bool ContentSecurityPolicyIsSandboxed( diff --git a/extensions/common/csp_validator.h b/extensions/common/csp_validator.h index e8aa78c..93676b0 100644 --- a/extensions/common/csp_validator.h +++ b/extensions/common/csp_validator.h @@ -43,8 +43,13 @@ enum Options { // case for extensions. Platform apps disallow it. // // |options| is a bitmask of Options. -bool ContentSecurityPolicyIsSecure( - const std::string& policy, int options); +// +// If |warnings| is not NULL, any validation errors are appended to |warnings|. +// Returns the sanitized policy. +std::string SanitizeContentSecurityPolicy( + const std::string& policy, + int options, + std::vector<InstallWarning>* warnings); // Checks whether the given |policy| enforces a unique origin sandbox as // defined by http://www.whatwg.org/specs/web-apps/current-work/multipage/ diff --git a/extensions/common/csp_validator_unittest.cc b/extensions/common/csp_validator_unittest.cc index 1afa0b1..a9728f9 100644 --- a/extensions/common/csp_validator_unittest.cc +++ b/extensions/common/csp_validator_unittest.cc @@ -3,16 +3,112 @@ // found in the LICENSE file. #include "extensions/common/csp_validator.h" +#include "extensions/common/error_utils.h" +#include "extensions/common/install_warning.h" +#include "extensions/common/manifest_constants.h" #include "testing/gtest/include/gtest/gtest.h" using extensions::csp_validator::ContentSecurityPolicyIsLegal; -using extensions::csp_validator::ContentSecurityPolicyIsSecure; +using extensions::csp_validator::SanitizeContentSecurityPolicy; using extensions::csp_validator::ContentSecurityPolicyIsSandboxed; using extensions::csp_validator::OPTIONS_NONE; using extensions::csp_validator::OPTIONS_ALLOW_UNSAFE_EVAL; using extensions::csp_validator::OPTIONS_ALLOW_INSECURE_OBJECT_SRC; +using extensions::ErrorUtils; +using extensions::InstallWarning; using extensions::Manifest; +namespace { + +std::string InsecureValueWarning(const std::string& directive, + const std::string& value) { + return ErrorUtils::FormatErrorMessage( + extensions::manifest_errors::kInvalidCSPInsecureValue, value, directive); +} + +std::string MissingSecureSrcWarning(const std::string& directive) { + return ErrorUtils::FormatErrorMessage( + extensions::manifest_errors::kInvalidCSPMissingSecureSrc, directive); +} + +testing::AssertionResult CheckSanitizeCSP( + const std::string& policy, + int options, + const std::string& expected_csp, + const std::vector<std::string>& expected_warnings) { + std::vector<InstallWarning> actual_warnings; + std::string actual_csp = SanitizeContentSecurityPolicy(policy, + options, + &actual_warnings); + if (actual_csp != expected_csp) + return testing::AssertionFailure() + << "SanitizeContentSecurityPolicy returned an unexpected CSP.\n" + << "Expected CSP: " << expected_csp << "\n" + << " Actual CSP: " << actual_csp; + + if (expected_warnings.size() != actual_warnings.size()) { + testing::Message msg; + msg << "Expected " << expected_warnings.size() + << " warnings, but got " << actual_warnings.size(); + for (size_t i = 0; i < actual_warnings.size(); ++i) + msg << "\nWarning " << i << " " << actual_warnings[i].message; + return testing::AssertionFailure() << msg; + } + + for (size_t i = 0; i < expected_warnings.size(); ++i) { + if (expected_warnings[i] != actual_warnings[i].message) + return testing::AssertionFailure() + << "Unexpected warning from SanitizeContentSecurityPolicy.\n" + << "Expected warning[" << i << "]: " << expected_warnings[i] + << " Actual warning[" << i << "]: " << actual_warnings[i].message; + } + return testing::AssertionSuccess(); +} + +testing::AssertionResult CheckSanitizeCSP(const std::string& policy, + int options) { + return CheckSanitizeCSP(policy, options, policy, std::vector<std::string>()); +} + +testing::AssertionResult CheckSanitizeCSP(const std::string& policy, + int options, + const std::string& expected_csp) { + std::vector<std::string> expected_warnings; + return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings); +} + +testing::AssertionResult CheckSanitizeCSP(const std::string& policy, + int options, + const std::string& expected_csp, + const std::string& warning1) { + std::vector<std::string> expected_warnings(1, warning1); + return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings); +} + +testing::AssertionResult CheckSanitizeCSP(const std::string& policy, + int options, + const std::string& expected_csp, + const std::string& warning1, + const std::string& warning2) { + std::vector<std::string> expected_warnings(1, warning1); + expected_warnings.push_back(warning2); + return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings); +} + +testing::AssertionResult CheckSanitizeCSP(const std::string& policy, + int options, + const std::string& expected_csp, + const std::string& warning1, + const std::string& warning2, + const std::string& warning3) { + std::vector<std::string> expected_warnings(1, warning1); + expected_warnings.push_back(warning2); + expected_warnings.push_back(warning3); + return CheckSanitizeCSP(policy, options, expected_csp, expected_warnings); +} + +}; // namespace + TEST(ExtensionCSPValidator, IsLegal) { EXPECT_TRUE(ContentSecurityPolicyIsLegal("foo")); EXPECT_TRUE(ContentSecurityPolicyIsLegal( @@ -26,188 +122,277 @@ TEST(ExtensionCSPValidator, IsLegal) { } TEST(ExtensionCSPValidator, IsSecure) { - EXPECT_FALSE( - ContentSecurityPolicyIsSecure(std::string(), OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure("img-src https://google.com", - OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src *", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'none'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' ftp://google.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://google.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src *; default-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self'; default-src *", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self'; default-src *; script-src *; script-src 'self'", - OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self'; default-src *; script-src 'self'; script-src *", - OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + std::string(), OPTIONS_ALLOW_UNSAFE_EVAL, + "script-src 'self' chrome-extension-resource:; object-src 'self';", + MissingSecureSrcWarning("script-src"), + MissingSecureSrcWarning("object-src"))); + EXPECT_TRUE(CheckSanitizeCSP( + "img-src https://google.com", OPTIONS_ALLOW_UNSAFE_EVAL, + "img-src https://google.com; script-src 'self'" + " chrome-extension-resource:; object-src 'self';", + MissingSecureSrcWarning("script-src"), + MissingSecureSrcWarning("object-src"))); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src a b", OPTIONS_ALLOW_UNSAFE_EVAL, + "script-src; object-src 'self';", + InsecureValueWarning("script-src", "a"), + InsecureValueWarning("script-src", "b"), + MissingSecureSrcWarning("object-src"))); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src *; script-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( + EXPECT_TRUE(CheckSanitizeCSP( + "default-src *", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src;", + InsecureValueWarning("default-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'none';", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' ftp://google.com", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "ftp://google.com"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)); + + EXPECT_TRUE(CheckSanitizeCSP( + "default-src *; default-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src; default-src 'self';", + InsecureValueWarning("default-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self'; default-src *;", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self'; default-src;")); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self'; default-src *; script-src *; script-src 'self'", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self'; default-src; script-src; script-src 'self';", + InsecureValueWarning("script-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self'; default-src *; script-src 'self'; script-src *;", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self'; default-src; script-src 'self'; script-src;")); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src *; script-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src; script-src 'self';", + InsecureValueWarning("default-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( "default-src *; script-src 'self'; img-src 'self'", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src; script-src 'self'; img-src 'self';", + InsecureValueWarning("default-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src *; script-src 'self'; object-src 'self';", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src; script-src 'self'; object-src 'self';")); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'unsafe-eval';", OPTIONS_ALLOW_UNSAFE_EVAL)); + + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'unsafe-eval'", OPTIONS_NONE, + "default-src;", + InsecureValueWarning("default-src", "'unsafe-eval'"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'unsafe-inline'", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src;", + InsecureValueWarning("default-src", "'unsafe-inline'"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'unsafe-inline' 'none'", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'none';", + InsecureValueWarning("default-src", "'unsafe-inline'"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://google.com", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "http://google.com"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' chrome://resources;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' chrome-extension://aabbcc;", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src *; script-src 'self'; object-src 'self'", - OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src 'self'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'unsafe-eval'", OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'unsafe-eval'", OPTIONS_NONE)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'unsafe-inline'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'unsafe-inline' 'none'", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://google.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://google.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' chrome://resources", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' chrome-extension://aabbcc", - OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' chrome-extension-resource://aabbcc", - OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https:", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' http:", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' google.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' *", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' *:*", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' *:*/", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' *:*/path", OPTIONS_ALLOW_UNSAFE_EVAL)); - // "https://" is an invalid CSP, so it will be ignored by Blink. - // TODO(robwu): Change to EXPECT_FALSE once http://crbug.com/434773 is fixed. - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*:*", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*:*/", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*:*/path", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.*.google.com:*/", - OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://www.*.google.com/", + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' chrome-extension-resource://aabbcc;", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https:", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https:"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http:", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "http:"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' google.com", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "google.com"))); + + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' *", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' *:*", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "*:*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' *:*/", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "*:*/"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' *:*/path", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "*:*/path"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*:*", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://*:*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*:*/", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://*:*/"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*:*/path", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://*:*/path"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.com", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://*.com"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://*.*.google.com/"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.*.google.com:*/", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://*.*.google.com:*/"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://www.*.google.com/", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://www.*.google.com/"))); + EXPECT_TRUE(CheckSanitizeCSP( "default-src 'self' https://www.*.google.com:*/", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "https://www.*.google.com:*/"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' chrome://*", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "chrome://*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' chrome-extension://*", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "chrome-extension://*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' chrome-extension://", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "chrome-extension://"))); + + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.google.com:1;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.google.com:*;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.google.com:1/;", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' chrome://*", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' chrome-extension://*", OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.google.com", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.google.com:1", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.google.com:*", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.google.com:1/", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.google.com:*/", OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://127.0.0.1", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://localhost", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://lOcAlHoSt", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://127.0.0.1:9999", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://localhost:8888", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' http://127.0.0.1.example.com", + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.google.com:*/;", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( + + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://127.0.0.1;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://localhost;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://lOcAlHoSt;", OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self' http://localhost;")); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://127.0.0.1:9999;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://localhost:8888;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' http://127.0.0.1.example.com", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "http://127.0.0.1.example.com"))); + EXPECT_TRUE(CheckSanitizeCSP( "default-src 'self' http://localhost.example.com", - OPTIONS_ALLOW_UNSAFE_EVAL)); + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "http://localhost.example.com"))); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' blob:", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' blob:;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( "default-src 'self' blob:http://example.com/XXX", - OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' filesystem:", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "default-src 'self' filesystem:http://example.com/XXX", - OPTIONS_ALLOW_UNSAFE_EVAL)); + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "blob:http://example.com/xxx"))); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' filesystem:;", OPTIONS_ALLOW_UNSAFE_EVAL)); + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' filesystem:http://example.com/XX", + OPTIONS_ALLOW_UNSAFE_EVAL, + "default-src 'self';", + InsecureValueWarning("default-src", "filesystem:http://example.com/xx"))); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://*.googleapis.com", + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://*.googleapis.com;", OPTIONS_ALLOW_UNSAFE_EVAL)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' https://x.googleapis.com", + EXPECT_TRUE(CheckSanitizeCSP( + "default-src 'self' https://x.googleapis.com;", OPTIONS_ALLOW_UNSAFE_EVAL)); - // "chrome-extension://" is an invalid CSP and ignored by Blink, but extension - // authors have been using this string anyway, so we cannot refuse this string - // until extensions can be loaded with an invalid CSP. http://crbug.com/434773 - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "default-src 'self' chrome-extension://", OPTIONS_ALLOW_UNSAFE_EVAL)); - - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src *", OPTIONS_NONE)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src *", OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src *; plugin-types application/pdf", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src *; " - "plugin-types application/x-shockwave-flash", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src *; " - "plugin-types application/x-shockwave-flash application/pdf", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src http://www.example.com; " - "plugin-types application/pdf", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "object-src http://www.example.com blob:; script-src 'self'; " - "plugin-types application/pdf", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_TRUE(ContentSecurityPolicyIsSecure( - "script-src 'self'; object-src http://*.example.com; " - "plugin-types application/pdf", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( - "script-src *; object-src *; plugin-types application/pdf", - OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); + + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src *", OPTIONS_NONE, + "script-src 'self'; object-src;", + InsecureValueWarning("object-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src *", OPTIONS_ALLOW_INSECURE_OBJECT_SRC, + "script-src 'self'; object-src;", + InsecureValueWarning("object-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src *; plugin-types application/pdf;", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src *; " + "plugin-types application/x-shockwave-flash", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC, + "script-src 'self'; object-src; " + "plugin-types application/x-shockwave-flash;", + InsecureValueWarning("object-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src *; " + "plugin-types application/x-shockwave-flash application/pdf;", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC, + "script-src 'self'; object-src; " + "plugin-types application/x-shockwave-flash application/pdf;", + InsecureValueWarning("object-src", "*"))); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src http://www.example.com; " + "plugin-types application/pdf;", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); + EXPECT_TRUE(CheckSanitizeCSP( + "object-src http://www.example.com blob:; script-src 'self'; " + "plugin-types application/pdf;", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src 'self'; object-src http://*.example.com; " + "plugin-types application/pdf;", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC)); + EXPECT_TRUE(CheckSanitizeCSP( + "script-src *; object-src *; plugin-types application/pdf;", + OPTIONS_ALLOW_INSECURE_OBJECT_SRC, + "script-src; object-src *; plugin-types application/pdf;", + InsecureValueWarning("script-src", "*"))); } TEST(ExtensionCSPValidator, IsSandboxed) { diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index 40b7d4e..4565184 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc @@ -314,10 +314,15 @@ const char kInvalidContentPackSites[] = "Invalid value for Content Pack sites - files must be strings."; const char kInvalidContentScript[] = "Invalid value for 'content_scripts[*]'."; -const char kInvalidContentSecurityPolicy[] = - "Invalid value for 'content_security_policy'."; const char kInvalidContentScriptsList[] = "Invalid value for 'content_scripts'."; +const char kInvalidContentSecurityPolicy[] = + "Invalid value for 'content_security_policy'."; +const char kInvalidCSPInsecureValue[] = + "Ignored insecure CSP value \"*\" in directive '*'."; +const char kInvalidCSPMissingSecureSrc[] = + "CSP directive '*' must be specified (either explicitly, or implicitly via" + " 'default-src') and must whitelist only secure resources."; const char kInvalidCss[] = "Invalid value for 'content_scripts[*].css[*]'."; const char kInvalidCssList[] = @@ -627,14 +632,6 @@ const char kInvalidWebURLs[] = "Invalid value for 'app.urls'."; const char kInvalidZipHash[] = "Required key 'zip_hash' is missing or invalid."; -const char kInsecureContentSecurityPolicy[] = - "Invalid value for 'content_security_policy': Both 'script-src' and" - " 'object-src' directives must be specified (either explicitly, or" - " implicitly via 'default-src'), and both must whitelist only secure" - " resources. You may include any of the following sources: \"'self'\"," - " \"'unsafe-eval'\", \"http://127.0.0.1\", \"http://localhost\", or any" - " \"https://\" or \"chrome-extension://\" origin. For more information," - " see http://developer.chrome.com/extensions/contentSecurityPolicy.html"; const char kKeyIsDeprecatedWithReplacement[] = "Key \"*\" is deprecated. Key \"*\" should be used instead."; const char kLauncherPagePageRequired[] = diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h index d395033..7ab779c 100644 --- a/extensions/common/manifest_constants.h +++ b/extensions/common/manifest_constants.h @@ -279,6 +279,8 @@ extern const char kInvalidContentPackSites[]; extern const char kInvalidContentScript[]; extern const char kInvalidContentScriptsList[]; extern const char kInvalidContentSecurityPolicy[]; +extern const char kInvalidCSPInsecureValue[]; +extern const char kInvalidCSPMissingSecureSrc[]; extern const char kInvalidCss[]; extern const char kInvalidCssList[]; extern const char kInvalidDefaultLocale[]; diff --git a/extensions/common/manifest_handlers/csp_info.cc b/extensions/common/manifest_handlers/csp_info.cc index 2c3838f..e756995 100644 --- a/extensions/common/manifest_handlers/csp_info.cc +++ b/extensions/common/manifest_handlers/csp_info.cc @@ -9,6 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "extensions/common/csp_validator.h" +#include "extensions/common/install_warning.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_handlers/sandboxed_page_info.h" @@ -18,12 +19,12 @@ namespace keys = manifest_keys; namespace errors = manifest_errors; using csp_validator::ContentSecurityPolicyIsLegal; -using csp_validator::ContentSecurityPolicyIsSecure; +using csp_validator::SanitizeContentSecurityPolicy; namespace { const char kDefaultContentSecurityPolicy[] = - "script-src 'self' chrome-extension-resource:; object-src 'self'"; + "script-src 'self' chrome-extension-resource:; object-src 'self';"; #define PLATFORM_APP_LOCAL_CSP_SOURCES \ "'self' data: chrome-extension-resource:" @@ -31,18 +32,18 @@ const char kDefaultPlatformAppContentSecurityPolicy[] = // Platform apps can only use local resources by default. "default-src 'self' chrome-extension-resource:;" // For remote resources, they can fetch them via XMLHttpRequest. - "connect-src *;" + " connect-src *;" // And serve them via data: or same-origin (blob:, filesystem:) URLs - "style-src " PLATFORM_APP_LOCAL_CSP_SOURCES " 'unsafe-inline';" - "img-src " PLATFORM_APP_LOCAL_CSP_SOURCES ";" - "frame-src " PLATFORM_APP_LOCAL_CSP_SOURCES ";" - "font-src " PLATFORM_APP_LOCAL_CSP_SOURCES ";" + " style-src " PLATFORM_APP_LOCAL_CSP_SOURCES " 'unsafe-inline';" + " img-src " PLATFORM_APP_LOCAL_CSP_SOURCES ";" + " frame-src " PLATFORM_APP_LOCAL_CSP_SOURCES ";" + " font-src " PLATFORM_APP_LOCAL_CSP_SOURCES ";" // Media can be loaded from remote resources since: // 1. <video> and <audio> have good fallback behavior when offline or under // spotty connectivity. // 2. Fetching via XHR and serving via blob: URLs currently does not allow // streaming or partial buffering. - "media-src *;"; + " media-src *;"; int GetValidatorOptions(Extension* extension) { int options = csp_validator::OPTIONS_NONE; @@ -108,8 +109,10 @@ bool CSPHandler::Parse(Extension* extension, base::string16* error) { kDefaultPlatformAppContentSecurityPolicy : kDefaultContentSecurityPolicy; - CHECK(ContentSecurityPolicyIsSecure(content_security_policy, - GetValidatorOptions(extension))); + CHECK_EQ(content_security_policy, + SanitizeContentSecurityPolicy(content_security_policy, + GetValidatorOptions(extension), + NULL)); extension->SetManifestData(keys::kContentSecurityPolicy, new CSPInfo(content_security_policy)); } @@ -125,11 +128,14 @@ bool CSPHandler::Parse(Extension* extension, base::string16* error) { *error = base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); return false; } - if (extension->manifest_version() >= 2 && - !ContentSecurityPolicyIsSecure(content_security_policy, - GetValidatorOptions(extension))) { - *error = base::ASCIIToUTF16(errors::kInsecureContentSecurityPolicy); - return false; + std::string sanitized_csp; + if (extension->manifest_version() >= 2) { + std::vector<InstallWarning> warnings; + content_security_policy = + SanitizeContentSecurityPolicy(content_security_policy, + GetValidatorOptions(extension), + &warnings); + extension->AddInstallWarnings(warnings); } extension->SetManifestData(keys::kContentSecurityPolicy, |