1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/common/manifest_handlers/csp_info.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#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"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
using csp_validator::ContentSecurityPolicyIsLegal;
using csp_validator::SanitizeContentSecurityPolicy;
namespace {
const char kDefaultContentSecurityPolicy[] =
"script-src 'self' blob: filesystem: chrome-extension-resource:; "
"object-src 'self' blob: filesystem:;";
#define PLATFORM_APP_LOCAL_CSP_SOURCES \
"'self' blob: filesystem: data: chrome-extension-resource:"
const char kDefaultPlatformAppContentSecurityPolicy[] =
// Platform apps can only use local resources by default.
"default-src 'self' blob: filesystem: chrome-extension-resource:;"
// For remote resources, they can fetch them via XMLHttpRequest.
" connect-src * data: blob: filesystem:;"
// 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 ";"
// 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 * data: blob: filesystem:;";
int GetValidatorOptions(Extension* extension) {
int options = csp_validator::OPTIONS_NONE;
// crbug.com/146487
if (extension->GetType() == Manifest::TYPE_EXTENSION ||
extension->GetType() == Manifest::TYPE_LEGACY_PACKAGED_APP) {
options |= csp_validator::OPTIONS_ALLOW_UNSAFE_EVAL;
}
// Component extensions can specify an insecure object-src directive. This
// should be safe because non-NPAPI plugins should load in a sandboxed process
// and only allow communication via postMessage. Flash is an exception since
// it allows scripting into the embedder page, but even then it should
// disallow cross-origin scripting. At some point we may want to consider
// allowing this publicly.
if (extensions::Manifest::IsComponentLocation(extension->location()))
options |= csp_validator::OPTIONS_ALLOW_INSECURE_OBJECT_SRC;
return options;
}
} // namespace
CSPInfo::CSPInfo(const std::string& security_policy)
: content_security_policy(security_policy) {
}
CSPInfo::~CSPInfo() {
}
// static
const std::string& CSPInfo::GetContentSecurityPolicy(
const Extension* extension) {
CSPInfo* csp_info = static_cast<CSPInfo*>(
extension->GetManifestData(keys::kContentSecurityPolicy));
return csp_info ? csp_info->content_security_policy : base::EmptyString();
}
// static
const std::string& CSPInfo::GetResourceContentSecurityPolicy(
const Extension* extension,
const std::string& relative_path) {
return SandboxedPageInfo::IsSandboxedPage(extension, relative_path) ?
SandboxedPageInfo::GetContentSecurityPolicy(extension) :
GetContentSecurityPolicy(extension);
}
CSPHandler::CSPHandler(bool is_platform_app)
: is_platform_app_(is_platform_app) {
}
CSPHandler::~CSPHandler() {
}
bool CSPHandler::Parse(Extension* extension, base::string16* error) {
const std::string key = Keys()[0];
if (!extension->manifest()->HasPath(key)) {
if (extension->manifest_version() >= 2) {
// TODO(abarth): Should we continue to let extensions override the
// default Content-Security-Policy?
std::string content_security_policy = is_platform_app_ ?
kDefaultPlatformAppContentSecurityPolicy :
kDefaultContentSecurityPolicy;
CHECK_EQ(content_security_policy,
SanitizeContentSecurityPolicy(content_security_policy,
GetValidatorOptions(extension),
NULL));
extension->SetManifestData(keys::kContentSecurityPolicy,
new CSPInfo(content_security_policy));
}
return true;
}
std::string content_security_policy;
if (!extension->manifest()->GetString(key, &content_security_policy)) {
*error = base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
return false;
}
if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
*error = base::ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
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,
new CSPInfo(content_security_policy));
return true;
}
bool CSPHandler::AlwaysParseForType(Manifest::Type type) const {
if (is_platform_app_)
return type == Manifest::TYPE_PLATFORM_APP;
else
return type == Manifest::TYPE_EXTENSION ||
type == Manifest::TYPE_LEGACY_PACKAGED_APP;
}
const std::vector<std::string> CSPHandler::Keys() const {
const std::string& key = is_platform_app_ ?
keys::kPlatformAppContentSecurityPolicy : keys::kContentSecurityPolicy;
return SingleKey(key);
}
} // namespace extensions
|