OLD | NEW |
---|---|
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-pnacl" | |
36 }; | |
37 | |
30 struct DirectiveStatus { | 38 struct DirectiveStatus { |
31 explicit DirectiveStatus(const char* name) | 39 explicit DirectiveStatus(const char* name) |
32 : directive_name(name) | 40 : directive_name(name) |
33 , seen_in_policy(false) | 41 , seen_in_policy(false) |
34 , is_secure(false) { | 42 , is_secure(false) { |
35 } | 43 } |
36 | 44 |
37 const char* directive_name; | 45 const char* directive_name; |
38 bool seen_in_policy; | 46 bool seen_in_policy; |
39 bool is_secure; | 47 bool is_secure; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 int options) { | 157 int options) { |
150 if (status->seen_in_policy) | 158 if (status->seen_in_policy) |
151 return false; | 159 return false; |
152 if (directive_name != status->directive_name) | 160 if (directive_name != status->directive_name) |
153 return false; | 161 return false; |
154 status->seen_in_policy = true; | 162 status->seen_in_policy = true; |
155 status->is_secure = HasOnlySecureTokens(tokenizer, options); | 163 status->is_secure = HasOnlySecureTokens(tokenizer, options); |
156 return true; | 164 return true; |
157 } | 165 } |
158 | 166 |
167 // Parses the plugin-types directive and returns the list of mime types | |
168 // specified in |plugin_types|. | |
169 bool ParsePluginTypes(const std::string& directive_name, | |
170 base::StringTokenizer& tokenizer, | |
171 std::vector<std::string>* plugin_types) { | |
172 DCHECK(plugin_types); | |
173 | |
174 if (directive_name != kPluginTypes || !plugin_types->empty()) | |
175 return false; | |
176 | |
177 while (tokenizer.GetNext()) { | |
178 std::string mime_type = tokenizer.token(); | |
179 base::StringToLowerASCII(&mime_type); | |
180 // Since we're comparing the mime types to a whitelist, we don't check them | |
181 // for strict validity right now. | |
182 plugin_types->push_back(mime_type); | |
183 } | |
184 | |
185 return true; | |
186 } | |
187 | |
188 // Returns true if the |plugin_type| is one of the fully sandboxed plugin types. | |
189 bool PluginTypeAllowed(const std::string& plugin_type) { | |
190 for (size_t i = 0; i < arraysize(kSandboxedPluginTypes); ++i) { | |
191 if (plugin_type == kSandboxedPluginTypes[i]) | |
192 return true; | |
193 } | |
194 return false; | |
195 } | |
196 | |
197 // Returns true if the policy is allowed to contain an insecure object-src | |
198 // directive. This requires OPTIONS_ALLOW_INSECURE_OBJECT_SRC to be specified | |
199 // as an option and the plugin-types that can be loaded must be restricted to | |
200 // the set specified in kSandboxedPluginTypes. | |
201 bool AllowedToHaveInsecureObjectSrc( | |
202 int options, | |
203 const std::vector<std::string>& plugin_types) { | |
204 if (!(options & OPTIONS_ALLOW_INSECURE_OBJECT_SRC)) | |
205 return false; | |
206 | |
207 // plugin-types must be specified. | |
208 if (plugin_types.empty()) | |
209 return false; | |
210 | |
211 for (size_t i = 0; i < plugin_types.size(); ++i) { | |
not at google - send to devlin
2014/11/25 17:08:46
Perhaps use newfangled for-loop syntax, if you lik
raymes
2014/11/25 22:31:16
Done.
| |
212 if (!PluginTypeAllowed(plugin_types[i])) | |
213 return false; | |
214 } | |
215 | |
216 return true; | |
217 } | |
218 | |
159 } // namespace | 219 } // namespace |
160 | 220 |
161 bool ContentSecurityPolicyIsLegal(const std::string& policy) { | 221 bool ContentSecurityPolicyIsLegal(const std::string& policy) { |
162 // We block these characters to prevent HTTP header injection when | 222 // We block these characters to prevent HTTP header injection when |
163 // representing the content security policy as an HTTP header. | 223 // representing the content security policy as an HTTP header. |
164 const char kBadChars[] = {',', '\r', '\n', '\0'}; | 224 const char kBadChars[] = {',', '\r', '\n', '\0'}; |
165 | 225 |
166 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == | 226 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == |
167 std::string::npos; | 227 std::string::npos; |
168 } | 228 } |
169 | 229 |
170 bool ContentSecurityPolicyIsSecure(const std::string& policy, | 230 bool ContentSecurityPolicyIsSecure(const std::string& policy, |
171 int options) { | 231 int options) { |
172 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. | 232 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. |
173 std::vector<std::string> directives; | 233 std::vector<std::string> directives; |
174 base::SplitString(policy, ';', &directives); | 234 base::SplitString(policy, ';', &directives); |
175 | 235 |
176 DirectiveStatus default_src_status(kDefaultSrc); | 236 DirectiveStatus default_src_status(kDefaultSrc); |
177 DirectiveStatus script_src_status(kScriptSrc); | 237 DirectiveStatus script_src_status(kScriptSrc); |
178 DirectiveStatus object_src_status(kObjectSrc); | 238 DirectiveStatus object_src_status(kObjectSrc); |
179 | 239 |
240 std::vector<std::string> plugin_types; | |
241 | |
180 for (size_t i = 0; i < directives.size(); ++i) { | 242 for (size_t i = 0; i < directives.size(); ++i) { |
181 std::string& input = directives[i]; | 243 std::string& input = directives[i]; |
182 base::StringTokenizer tokenizer(input, " \t\r\n"); | 244 base::StringTokenizer tokenizer(input, " \t\r\n"); |
183 if (!tokenizer.GetNext()) | 245 if (!tokenizer.GetNext()) |
184 continue; | 246 continue; |
185 | 247 |
186 std::string directive_name = tokenizer.token(); | 248 std::string directive_name = tokenizer.token(); |
187 base::StringToLowerASCII(&directive_name); | 249 base::StringToLowerASCII(&directive_name); |
188 | 250 |
189 if (UpdateStatus(directive_name, tokenizer, &default_src_status, options)) | 251 if (UpdateStatus(directive_name, tokenizer, &default_src_status, options)) |
190 continue; | 252 continue; |
191 if (UpdateStatus(directive_name, tokenizer, &script_src_status, options)) | 253 if (UpdateStatus(directive_name, tokenizer, &script_src_status, options)) |
192 continue; | 254 continue; |
193 if (UpdateStatus(directive_name, tokenizer, &object_src_status, options)) | 255 if (UpdateStatus(directive_name, tokenizer, &object_src_status, options)) |
194 continue; | 256 continue; |
257 if (ParsePluginTypes(directive_name, tokenizer, &plugin_types)) | |
258 continue; | |
195 } | 259 } |
196 | 260 |
197 if (script_src_status.seen_in_policy && !script_src_status.is_secure) | 261 if (script_src_status.seen_in_policy && !script_src_status.is_secure) |
198 return false; | 262 return false; |
199 | 263 |
200 if (object_src_status.seen_in_policy && !object_src_status.is_secure) { | 264 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 | 265 // Note that this does not fully check the object-src source list for |
202 // validity but Blink will do this anyway. | 266 // validity but Blink will do this anyway. |
203 if (!(options & OPTIONS_ALLOW_INSECURE_OBJECT_SRC)) | 267 if (!AllowedToHaveInsecureObjectSrc(options, plugin_types)) |
204 return false; | 268 return false; |
205 } | 269 } |
206 | 270 |
207 if (default_src_status.seen_in_policy && !default_src_status.is_secure) { | 271 if (default_src_status.seen_in_policy && !default_src_status.is_secure) { |
208 return script_src_status.seen_in_policy && | 272 return script_src_status.seen_in_policy && |
209 object_src_status.seen_in_policy; | 273 object_src_status.seen_in_policy; |
210 } | 274 } |
211 | 275 |
212 return default_src_status.seen_in_policy || | 276 return default_src_status.seen_in_policy || |
213 (script_src_status.seen_in_policy && object_src_status.seen_in_policy); | 277 (script_src_status.seen_in_policy && object_src_status.seen_in_policy); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 } | 314 } |
251 } | 315 } |
252 } | 316 } |
253 | 317 |
254 return seen_sandbox; | 318 return seen_sandbox; |
255 } | 319 } |
256 | 320 |
257 } // namespace csp_validator | 321 } // namespace csp_validator |
258 | 322 |
259 } // namespace extensions | 323 } // namespace extensions |
OLD | NEW |