1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/common/manifest_handlers/csp_info.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "extensions/common/csp_validator.h"
12 #include "extensions/common/install_warning.h"
13 #include "extensions/common/manifest_constants.h"
14 #include "extensions/common/manifest_handlers/sandboxed_page_info.h"
16 namespace extensions
{
18 namespace keys
= manifest_keys
;
19 namespace errors
= manifest_errors
;
21 using csp_validator::ContentSecurityPolicyIsLegal
;
22 using csp_validator::SanitizeContentSecurityPolicy
;
26 const char kDefaultContentSecurityPolicy
[] =
27 "script-src 'self' blob: filesystem: chrome-extension-resource:; "
28 "object-src 'self' blob: filesystem:;";
30 #define PLATFORM_APP_LOCAL_CSP_SOURCES \
31 "'self' blob: filesystem: data: chrome-extension-resource:"
33 const char kDefaultPlatformAppContentSecurityPolicy
[] =
34 // Platform apps can only use local resources by default.
35 "default-src 'self' blob: filesystem: chrome-extension-resource:;"
36 // For remote resources, they can fetch them via XMLHttpRequest.
38 // And serve them via data: or same-origin (blob:, filesystem:) URLs
39 " style-src " PLATFORM_APP_LOCAL_CSP_SOURCES
" 'unsafe-inline';"
40 " img-src " PLATFORM_APP_LOCAL_CSP_SOURCES
";"
41 " frame-src " PLATFORM_APP_LOCAL_CSP_SOURCES
";"
42 " font-src " PLATFORM_APP_LOCAL_CSP_SOURCES
";"
43 // Media can be loaded from remote resources since:
44 // 1. <video> and <audio> have good fallback behavior when offline or under
45 // spotty connectivity.
46 // 2. Fetching via XHR and serving via blob: URLs currently does not allow
47 // streaming or partial buffering.
50 int GetValidatorOptions(Extension
* extension
) {
51 int options
= csp_validator::OPTIONS_NONE
;
54 if (extension
->GetType() == Manifest::TYPE_EXTENSION
||
55 extension
->GetType() == Manifest::TYPE_LEGACY_PACKAGED_APP
) {
56 options
|= csp_validator::OPTIONS_ALLOW_UNSAFE_EVAL
;
59 // Component extensions can specify an insecure object-src directive. This
60 // should be safe because non-NPAPI plugins should load in a sandboxed process
61 // and only allow communication via postMessage. Flash is an exception since
62 // it allows scripting into the embedder page, but even then it should
63 // disallow cross-origin scripting. At some point we may want to consider
64 // allowing this publicly.
65 if (extensions::Manifest::IsComponentLocation(extension
->location()))
66 options
|= csp_validator::OPTIONS_ALLOW_INSECURE_OBJECT_SRC
;
73 CSPInfo::CSPInfo(const std::string
& security_policy
)
74 : content_security_policy(security_policy
) {
81 const std::string
& CSPInfo::GetContentSecurityPolicy(
82 const Extension
* extension
) {
83 CSPInfo
* csp_info
= static_cast<CSPInfo
*>(
84 extension
->GetManifestData(keys::kContentSecurityPolicy
));
85 return csp_info
? csp_info
->content_security_policy
: base::EmptyString();
89 const std::string
& CSPInfo::GetResourceContentSecurityPolicy(
90 const Extension
* extension
,
91 const std::string
& relative_path
) {
92 return SandboxedPageInfo::IsSandboxedPage(extension
, relative_path
) ?
93 SandboxedPageInfo::GetContentSecurityPolicy(extension
) :
94 GetContentSecurityPolicy(extension
);
97 CSPHandler::CSPHandler(bool is_platform_app
)
98 : is_platform_app_(is_platform_app
) {
101 CSPHandler::~CSPHandler() {
104 bool CSPHandler::Parse(Extension
* extension
, base::string16
* error
) {
105 const std::string key
= Keys()[0];
106 if (!extension
->manifest()->HasPath(key
)) {
107 if (extension
->manifest_version() >= 2) {
108 // TODO(abarth): Should we continue to let extensions override the
109 // default Content-Security-Policy?
110 std::string content_security_policy
= is_platform_app_
?
111 kDefaultPlatformAppContentSecurityPolicy
:
112 kDefaultContentSecurityPolicy
;
114 CHECK_EQ(content_security_policy
,
115 SanitizeContentSecurityPolicy(content_security_policy
,
116 GetValidatorOptions(extension
),
118 extension
->SetManifestData(keys::kContentSecurityPolicy
,
119 new CSPInfo(content_security_policy
));
124 std::string content_security_policy
;
125 if (!extension
->manifest()->GetString(key
, &content_security_policy
)) {
126 *error
= base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy
);
129 if (!ContentSecurityPolicyIsLegal(content_security_policy
)) {
130 *error
= base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy
);
133 std::string sanitized_csp
;
134 if (extension
->manifest_version() >= 2) {
135 std::vector
<InstallWarning
> warnings
;
136 content_security_policy
=
137 SanitizeContentSecurityPolicy(content_security_policy
,
138 GetValidatorOptions(extension
),
140 extension
->AddInstallWarnings(warnings
);
143 extension
->SetManifestData(keys::kContentSecurityPolicy
,
144 new CSPInfo(content_security_policy
));
148 bool CSPHandler::AlwaysParseForType(Manifest::Type type
) const {
149 if (is_platform_app_
)
150 return type
== Manifest::TYPE_PLATFORM_APP
;
152 return type
== Manifest::TYPE_EXTENSION
||
153 type
== Manifest::TYPE_LEGACY_PACKAGED_APP
;
156 const std::vector
<std::string
> CSPHandler::Keys() const {
157 const std::string
& key
= is_platform_app_
?
158 keys::kPlatformAppContentSecurityPolicy
: keys::kContentSecurityPolicy
;
159 return SingleKey(key
);
162 } // namespace extensions