Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: extensions/common/csp_validator.cc

Issue 760513003: Only allow insecure object-src directives for whitelisted mime types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@extensions-csp3
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « extensions/common/csp_validator.h ('k') | extensions/common/csp_validator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/common/csp_validator.h" 5 #include "extensions/common/csp_validator.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/strings/string_split.h" 9 #include "base/strings/string_split.h"
10 #include "base/strings/string_tokenizer.h" 10 #include "base/strings/string_tokenizer.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "content/public/common/url_constants.h" 12 #include "content/public/common/url_constants.h"
13 #include "extensions/common/constants.h" 13 #include "extensions/common/constants.h"
14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
15 15
16 namespace extensions { 16 namespace extensions {
17 17
18 namespace csp_validator { 18 namespace csp_validator {
19 19
20 namespace { 20 namespace {
21 21
22 const char kDefaultSrc[] = "default-src"; 22 const char kDefaultSrc[] = "default-src";
23 const char kScriptSrc[] = "script-src"; 23 const char kScriptSrc[] = "script-src";
24 const char kObjectSrc[] = "object-src"; 24 const char kObjectSrc[] = "object-src";
25 const char kPluginTypes[] = "plugin-types";
25 26
26 const char kSandboxDirectiveName[] = "sandbox"; 27 const char kSandboxDirectiveName[] = "sandbox";
27 const char kAllowSameOriginToken[] = "allow-same-origin"; 28 const char kAllowSameOriginToken[] = "allow-same-origin";
28 const char kAllowTopNavigation[] = "allow-top-navigation"; 29 const char kAllowTopNavigation[] = "allow-top-navigation";
29 30
31 // This is the list of plugin types which are fully sandboxed and are safe to
32 // load up in an extension, regardless of the URL they are navigated to.
33 const char* const kSandboxedPluginTypes[] = {
34 "application/pdf",
35 "application/x-google-chrome-pdf",
36 "application/x-pnacl"
37 };
38
30 struct DirectiveStatus { 39 struct DirectiveStatus {
31 explicit DirectiveStatus(const char* name) 40 explicit DirectiveStatus(const char* name)
32 : directive_name(name) 41 : directive_name(name)
33 , seen_in_policy(false) 42 , seen_in_policy(false)
34 , is_secure(false) { 43 , is_secure(false) {
35 } 44 }
36 45
37 const char* directive_name; 46 const char* directive_name;
38 bool seen_in_policy; 47 bool seen_in_policy;
39 bool is_secure; 48 bool is_secure;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 int options) { 158 int options) {
150 if (status->seen_in_policy) 159 if (status->seen_in_policy)
151 return false; 160 return false;
152 if (directive_name != status->directive_name) 161 if (directive_name != status->directive_name)
153 return false; 162 return false;
154 status->seen_in_policy = true; 163 status->seen_in_policy = true;
155 status->is_secure = HasOnlySecureTokens(tokenizer, options); 164 status->is_secure = HasOnlySecureTokens(tokenizer, options);
156 return true; 165 return true;
157 } 166 }
158 167
168 // Parses the plugin-types directive and returns the list of mime types
169 // specified in |plugin_types|.
170 bool ParsePluginTypes(const std::string& directive_name,
171 base::StringTokenizer& tokenizer,
172 std::vector<std::string>* plugin_types) {
173 DCHECK(plugin_types);
174
175 if (directive_name != kPluginTypes || !plugin_types->empty())
176 return false;
177
178 while (tokenizer.GetNext()) {
179 std::string mime_type = tokenizer.token();
180 base::StringToLowerASCII(&mime_type);
181 // Since we're comparing the mime types to a whitelist, we don't check them
182 // for strict validity right now.
183 plugin_types->push_back(mime_type);
184 }
185
186 return true;
187 }
188
189 // Returns true if the |plugin_type| is one of the fully sandboxed plugin types.
190 bool PluginTypeAllowed(const std::string& plugin_type) {
191 for (size_t i = 0; i < arraysize(kSandboxedPluginTypes); ++i) {
192 if (plugin_type == kSandboxedPluginTypes[i])
193 return true;
194 }
195 return false;
196 }
197
198 // Returns true if the policy is allowed to contain an insecure object-src
199 // directive. This requires OPTIONS_ALLOW_INSECURE_OBJECT_SRC to be specified
200 // as an option and the plugin-types that can be loaded must be restricted to
201 // the set specified in kSandboxedPluginTypes.
202 bool AllowedToHaveInsecureObjectSrc(
203 int options,
204 const std::vector<std::string>& plugin_types) {
205 if (!(options & OPTIONS_ALLOW_INSECURE_OBJECT_SRC))
206 return false;
207
208 // plugin-types must be specified.
209 if (plugin_types.empty())
210 return false;
211
212 for (const auto& plugin_type : plugin_types) {
213 if (!PluginTypeAllowed(plugin_type))
214 return false;
215 }
216
217 return true;
218 }
219
159 } // namespace 220 } // namespace
160 221
161 bool ContentSecurityPolicyIsLegal(const std::string& policy) { 222 bool ContentSecurityPolicyIsLegal(const std::string& policy) {
162 // We block these characters to prevent HTTP header injection when 223 // We block these characters to prevent HTTP header injection when
163 // representing the content security policy as an HTTP header. 224 // representing the content security policy as an HTTP header.
164 const char kBadChars[] = {',', '\r', '\n', '\0'}; 225 const char kBadChars[] = {',', '\r', '\n', '\0'};
165 226
166 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == 227 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) ==
167 std::string::npos; 228 std::string::npos;
168 } 229 }
169 230
170 bool ContentSecurityPolicyIsSecure(const std::string& policy, 231 bool ContentSecurityPolicyIsSecure(const std::string& policy,
171 int options) { 232 int options) {
172 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. 233 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm.
173 std::vector<std::string> directives; 234 std::vector<std::string> directives;
174 base::SplitString(policy, ';', &directives); 235 base::SplitString(policy, ';', &directives);
175 236
176 DirectiveStatus default_src_status(kDefaultSrc); 237 DirectiveStatus default_src_status(kDefaultSrc);
177 DirectiveStatus script_src_status(kScriptSrc); 238 DirectiveStatus script_src_status(kScriptSrc);
178 DirectiveStatus object_src_status(kObjectSrc); 239 DirectiveStatus object_src_status(kObjectSrc);
179 240
241 std::vector<std::string> plugin_types;
242
180 for (size_t i = 0; i < directives.size(); ++i) { 243 for (size_t i = 0; i < directives.size(); ++i) {
181 std::string& input = directives[i]; 244 std::string& input = directives[i];
182 base::StringTokenizer tokenizer(input, " \t\r\n"); 245 base::StringTokenizer tokenizer(input, " \t\r\n");
183 if (!tokenizer.GetNext()) 246 if (!tokenizer.GetNext())
184 continue; 247 continue;
185 248
186 std::string directive_name = tokenizer.token(); 249 std::string directive_name = tokenizer.token();
187 base::StringToLowerASCII(&directive_name); 250 base::StringToLowerASCII(&directive_name);
188 251
189 if (UpdateStatus(directive_name, tokenizer, &default_src_status, options)) 252 if (UpdateStatus(directive_name, tokenizer, &default_src_status, options))
190 continue; 253 continue;
191 if (UpdateStatus(directive_name, tokenizer, &script_src_status, options)) 254 if (UpdateStatus(directive_name, tokenizer, &script_src_status, options))
192 continue; 255 continue;
193 if (UpdateStatus(directive_name, tokenizer, &object_src_status, options)) 256 if (UpdateStatus(directive_name, tokenizer, &object_src_status, options))
194 continue; 257 continue;
258 if (ParsePluginTypes(directive_name, tokenizer, &plugin_types))
259 continue;
195 } 260 }
196 261
197 if (script_src_status.seen_in_policy && !script_src_status.is_secure) 262 if (script_src_status.seen_in_policy && !script_src_status.is_secure)
198 return false; 263 return false;
199 264
200 if (object_src_status.seen_in_policy && !object_src_status.is_secure) { 265 if (object_src_status.seen_in_policy && !object_src_status.is_secure) {
201 // Note that this does not fully check the object-src source list for 266 // Note that this does not fully check the object-src source list for
202 // validity but Blink will do this anyway. 267 // validity but Blink will do this anyway.
203 if (!(options & OPTIONS_ALLOW_INSECURE_OBJECT_SRC)) 268 if (!AllowedToHaveInsecureObjectSrc(options, plugin_types))
204 return false; 269 return false;
205 } 270 }
206 271
207 if (default_src_status.seen_in_policy && !default_src_status.is_secure) { 272 if (default_src_status.seen_in_policy && !default_src_status.is_secure) {
208 return script_src_status.seen_in_policy && 273 return script_src_status.seen_in_policy &&
209 object_src_status.seen_in_policy; 274 object_src_status.seen_in_policy;
210 } 275 }
211 276
212 return default_src_status.seen_in_policy || 277 return default_src_status.seen_in_policy ||
213 (script_src_status.seen_in_policy && object_src_status.seen_in_policy); 278 (script_src_status.seen_in_policy && object_src_status.seen_in_policy);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 } 315 }
251 } 316 }
252 } 317 }
253 318
254 return seen_sandbox; 319 return seen_sandbox;
255 } 320 }
256 321
257 } // namespace csp_validator 322 } // namespace csp_validator
258 323
259 } // namespace extensions 324 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/common/csp_validator.h ('k') | extensions/common/csp_validator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698