Commit c7338d52 authored by Karandeep Bhatia's avatar Karandeep Bhatia Committed by Commit Bot

Extensions: Restrict CSP dictionary to Manifest V3 and above.

Currently it was enabled on Trunk for MV2 extensions.

BUG=896041

Change-Id: Id35c9f3acdbd37739b0079ce04987aaef48ab27d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2462686Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Commit-Queue: Karan Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815806}
parent d4298b2e
...@@ -11,10 +11,8 @@ ...@@ -11,10 +11,8 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
#include "components/version_info/channel.h"
#include "extensions/common/csp_validator.h" #include "extensions/common/csp_validator.h"
#include "extensions/common/error_utils.h" #include "extensions/common/error_utils.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/common/install_warning.h" #include "extensions/common/install_warning.h"
#include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/sandboxed_page_info.h" #include "extensions/common/manifest_handlers/sandboxed_page_info.h"
...@@ -177,29 +175,16 @@ bool CSPHandler::Parse(Extension* extension, base::string16* error) { ...@@ -177,29 +175,16 @@ bool CSPHandler::Parse(Extension* extension, base::string16* error) {
// "extension_pages": "", // "extension_pages": "",
// "sandbox": "", // "sandbox": "",
// } // }
// The dictionary is supported (and mandated) for manifest v3 (and above)
// extensions.
const base::Value* csp = GetManifestPath(extension, key); const base::Value* csp = GetManifestPath(extension, key);
bool parse_as_dictionary = extension->manifest_version() >= 3;
// TODO(karandeepb): Remove the channel check since we don't plan to support if (parse_as_dictionary) {
// the CSP dictionary for Manifest V2. if (csp && !csp->is_dict()) {
bool csp_dictionary_supported = *error = GetInvalidManifestKeyError(key);
extension->GetType() == Manifest::TYPE_EXTENSION && return false;
(extension->manifest_version() >= 3 ||
GetCurrentChannel() == version_info::Channel::UNKNOWN);
if (csp_dictionary_supported) {
// CSP key as dictionary is mandatory for manifest v3 (and above)
// extensions.
if (extension->manifest_version() >= 3) {
if (csp && !csp->is_dict()) {
*error = GetInvalidManifestKeyError(key);
return false;
}
return ParseCSPDictionary(extension, error);
} }
return ParseCSPDictionary(extension, error);
// CSP key as dictionary is optional for manifest v2 extensions.
if (csp && csp->is_dict())
return ParseCSPDictionary(extension, error);
} }
if (!ParseExtensionPagesCSP(extension, error, key, false /* secure_only */, if (!ParseExtensionPagesCSP(extension, error, key, false /* secure_only */,
......
...@@ -131,55 +131,33 @@ TEST_F(CSPInfoUnitTest, CSPDictionary_ExtensionPages) { ...@@ -131,55 +131,33 @@ TEST_F(CSPInfoUnitTest, CSPDictionary_ExtensionPages) {
"worker-src 'self'; script-src; default-src 'self'"}, "worker-src 'self'; script-src; default-src 'self'"},
{"csp_empty_dictionary_valid.json", kDefaultSecureCSP}}; {"csp_empty_dictionary_valid.json", kDefaultSecureCSP}};
// Verify that keys::kContentSecurityPolicy key can be used as a dictionary on for (const auto& test_case : cases) {
// trunk. SCOPED_TRACE(base::StringPrintf("Testing %s.", test_case.file_name));
{ scoped_refptr<Extension> extension =
ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); LoadAndExpectSuccess(test_case.file_name);
for (const auto& test_case : cases) { ASSERT_TRUE(extension.get());
SCOPED_TRACE( EXPECT_EQ(test_case.csp, CSPInfo::GetExtensionPagesCSP(extension.get()));
base::StringPrintf("%s on channel %s", test_case.file_name, "trunk"));
scoped_refptr<Extension> extension =
LoadAndExpectSuccess(test_case.file_name);
ASSERT_TRUE(extension.get());
EXPECT_EQ(test_case.csp, CSPInfo::GetExtensionPagesCSP(extension.get()));
}
}
// Verify that keys::kContentSecurityPolicy key can't be used as a dictionary
// on Stable.
{
ScopedCurrentChannel channel(version_info::Channel::STABLE);
for (const auto& test_case : cases) {
SCOPED_TRACE(base::StringPrintf("%s on channel %s", test_case.file_name,
"stable"));
LoadAndExpectError(
test_case.file_name,
GetInvalidManifestKeyError(keys::kContentSecurityPolicy));
}
} }
{ Testcase testcases[] = {
ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); Testcase("csp_invalid_2.json",
Testcase testcases[] = { GetInvalidManifestKeyError(
Testcase("csp_invalid_2.json", keys::kContentSecurityPolicy_ExtensionPagesPath)),
GetInvalidManifestKeyError( Testcase("csp_invalid_3.json",
keys::kContentSecurityPolicy_ExtensionPagesPath)), GetInvalidManifestKeyError(
Testcase("csp_invalid_3.json", keys::kContentSecurityPolicy_ExtensionPagesPath)),
GetInvalidManifestKeyError( Testcase(
keys::kContentSecurityPolicy_ExtensionPagesPath)), "csp_missing_src.json",
Testcase( ErrorUtils::FormatErrorMessage(
"csp_missing_src.json", errors::kInvalidCSPMissingSecureSrc,
ErrorUtils::FormatErrorMessage( keys::kContentSecurityPolicy_ExtensionPagesPath, "script-src")),
errors::kInvalidCSPMissingSecureSrc, Testcase("csp_insecure_src.json",
keys::kContentSecurityPolicy_ExtensionPagesPath, "script-src")), ErrorUtils::FormatErrorMessage(
Testcase("csp_insecure_src.json", errors::kInvalidCSPInsecureValueError,
ErrorUtils::FormatErrorMessage( keys::kContentSecurityPolicy_ExtensionPagesPath,
errors::kInvalidCSPInsecureValueError, "'unsafe-eval'", "worker-src")),
keys::kContentSecurityPolicy_ExtensionPagesPath, };
"'unsafe-eval'", "worker-src")), RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
};
RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
}
} }
TEST_F(CSPInfoUnitTest, CSPDictionary_Sandbox) { TEST_F(CSPInfoUnitTest, CSPDictionary_Sandbox) {
...@@ -251,4 +229,10 @@ TEST_F(CSPInfoUnitTest, CSPDictionaryMandatoryForV3) { ...@@ -251,4 +229,10 @@ TEST_F(CSPInfoUnitTest, CSPDictionaryMandatoryForV3) {
} }
} }
// Ensure the CSP dictionary is disallowed for mv2 extensions.
TEST_F(CSPInfoUnitTest, CSPDictionaryDisallowedForV2) {
LoadAndExpectError("csp_dictionary_mv2.json",
GetInvalidManifestKeyError(keys::kContentSecurityPolicy));
}
} // namespace extensions } // namespace extensions
{
"name": "test",
"version": "0.1",
"manifest_version": 2,
"content_security_policy": {
"extension_pages" : "default-src 'none'"
}
}
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
"extension_pages" : "default-src 'none'" "extension_pages" : "default-src 'none'"
} }
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
"extension_pages" : "worker-src 'self'; script-src; default-src 'self'" "extension_pages" : "worker-src 'self'; script-src; default-src 'self'"
} }
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
} }
} }
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
"extension_pages" : "default-src 'none'; worker-src 'unsafe-eval';" "extension_pages" : "default-src 'none'; worker-src 'unsafe-eval';"
} }
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
"extension_pages" : {} "extension_pages" : {}
} }
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
"extension_pages" : "\r\n" "extension_pages" : "\r\n"
} }
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"content_security_policy": { "content_security_policy": {
"extension_pages" : "" "extension_pages" : ""
} }
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"sandbox": { "sandbox": {
"pages": ["test"], "pages": ["test"],
"content_security_policy": "sandbox;" "content_security_policy": "sandbox;"
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"sandbox": { "sandbox": {
"pages": ["test"], "pages": ["test"],
"content_security_policy": "sandbox;" "content_security_policy": "sandbox;"
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"sandbox": { "sandbox": {
"pages": ["test"] "pages": ["test"]
}, },
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"sandbox": { "sandbox": {
"pages": ["test"] "pages": ["test"]
}, },
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"sandbox": { "sandbox": {
"pages": ["test"] "pages": ["test"]
}, },
......
{ {
"name": "test", "name": "test",
"version": "0.1", "version": "0.1",
"manifest_version": 2, "manifest_version": 3,
"sandbox": { "sandbox": {
"pages": ["test"] "pages": ["test"]
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment