Chromium Code Reviews| 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 |