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-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 Loading... |
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 Loading... |
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 |
OLD | NEW |