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' chrome-extension-resource:; object-src 'self';";
29 #define PLATFORM_APP_LOCAL_CSP_SOURCES \
30 "'self' data: chrome-extension-resource:"
31 const char kDefaultPlatformAppContentSecurityPolicy
[] =
32 // Platform apps can only use local resources by default.
33 "default-src 'self' chrome-extension-resource:;"
34 // For remote resources, they can fetch them via XMLHttpRequest.
36 // And serve them via data: or same-origin (blob:, filesystem:) URLs
37 " style-src " PLATFORM_APP_LOCAL_CSP_SOURCES
" 'unsafe-inline';"
38 " img-src " PLATFORM_APP_LOCAL_CSP_SOURCES
";"
39 " frame-src " PLATFORM_APP_LOCAL_CSP_SOURCES
";"
40 " font-src " PLATFORM_APP_LOCAL_CSP_SOURCES
";"
41 // Media can be loaded from remote resources since:
42 // 1. <video> and <audio> have good fallback behavior when offline or under
43 // spotty connectivity.
44 // 2. Fetching via XHR and serving via blob: URLs currently does not allow
45 // streaming or partial buffering.
48 int GetValidatorOptions(Extension
* extension
) {
49 int options
= csp_validator::OPTIONS_NONE
;
52 if (extension
->GetType() == Manifest::TYPE_EXTENSION
||
53 extension
->GetType() == Manifest::TYPE_LEGACY_PACKAGED_APP
) {
54 options
|= csp_validator::OPTIONS_ALLOW_UNSAFE_EVAL
;
57 // Component extensions can specify an insecure object-src directive. This
58 // should be safe because non-NPAPI plugins should load in a sandboxed process
59 // and only allow communication via postMessage. Flash is an exception since
60 // it allows scripting into the embedder page, but even then it should
61 // disallow cross-origin scripting. At some point we may want to consider
62 // allowing this publicly.
63 if (extensions::Manifest::IsComponentLocation(extension
->location()))
64 options
|= csp_validator::OPTIONS_ALLOW_INSECURE_OBJECT_SRC
;
71 CSPInfo::CSPInfo(const std::string
& security_policy
)
72 : content_security_policy(security_policy
) {
79 const std::string
& CSPInfo::GetContentSecurityPolicy(
80 const Extension
* extension
) {
81 CSPInfo
* csp_info
= static_cast<CSPInfo
*>(
82 extension
->GetManifestData(keys::kContentSecurityPolicy
));
83 return csp_info
? csp_info
->content_security_policy
: base::EmptyString();
87 const std::string
& CSPInfo::GetResourceContentSecurityPolicy(
88 const Extension
* extension
,
89 const std::string
& relative_path
) {
90 return SandboxedPageInfo::IsSandboxedPage(extension
, relative_path
) ?
91 SandboxedPageInfo::GetContentSecurityPolicy(extension
) :
92 GetContentSecurityPolicy(extension
);
95 CSPHandler::CSPHandler(bool is_platform_app
)
96 : is_platform_app_(is_platform_app
) {
99 CSPHandler::~CSPHandler() {
102 bool CSPHandler::Parse(Extension
* extension
, base::string16
* error
) {
103 const std::string key
= Keys()[0];
104 if (!extension
->manifest()->HasPath(key
)) {
105 if (extension
->manifest_version() >= 2) {
106 // TODO(abarth): Should we continue to let extensions override the
107 // default Content-Security-Policy?
108 std::string content_security_policy
= is_platform_app_
?
109 kDefaultPlatformAppContentSecurityPolicy
:
110 kDefaultContentSecurityPolicy
;
112 CHECK_EQ(content_security_policy
,
113 SanitizeContentSecurityPolicy(content_security_policy
,
114 GetValidatorOptions(extension
),
116 extension
->SetManifestData(keys::kContentSecurityPolicy
,
117 new CSPInfo(content_security_policy
));
122 std::string content_security_policy
;
123 if (!extension
->manifest()->GetString(key
, &content_security_policy
)) {
124 *error
= base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy
);
127 if (!ContentSecurityPolicyIsLegal(content_security_policy
)) {
128 *error
= base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy
);
131 std::string sanitized_csp
;
132 if (extension
->manifest_version() >= 2) {
133 std::vector
<InstallWarning
> warnings
;
134 content_security_policy
=
135 SanitizeContentSecurityPolicy(content_security_policy
,
136 GetValidatorOptions(extension
),
138 extension
->AddInstallWarnings(warnings
);
141 extension
->SetManifestData(keys::kContentSecurityPolicy
,
142 new CSPInfo(content_security_policy
));
146 bool CSPHandler::AlwaysParseForType(Manifest::Type type
) const {
147 if (is_platform_app_
)
148 return type
== Manifest::TYPE_PLATFORM_APP
;
150 return type
== Manifest::TYPE_EXTENSION
||
151 type
== Manifest::TYPE_LEGACY_PACKAGED_APP
;
154 const std::vector
<std::string
> CSPHandler::Keys() const {
155 const std::string
& key
= is_platform_app_
?
156 keys::kPlatformAppContentSecurityPolicy
: keys::kContentSecurityPolicy
;
157 return SingleKey(key
);
160 } // namespace extensions