| 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 |