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 <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 | 21 |
| 22 namespace extensions { | 22 namespace extensions { |
| 23 | 23 |
| 24 namespace csp_validator { | 24 namespace csp_validator { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 const char kDefaultSrc[] = "default-src"; | 28 const char kDefaultSrc[] = "default-src"; |
| 29 const char kScriptSrc[] = "script-src"; | 29 const char kScriptSrc[] = "script-src"; |
| 30 const char kObjectSrc[] = "object-src"; | 30 const char kObjectSrc[] = "object-src"; |
| 31 const char kFrameSrc[] = "frame-src"; | |
| 32 const char kChildSrc[] = "child-src"; | |
| 33 | |
| 34 const char kDirectiveSeparator[] = ";"; | |
| 35 | |
| 31 const char kPluginTypes[] = "plugin-types"; | 36 const char kPluginTypes[] = "plugin-types"; |
| 32 | 37 |
| 33 const char kObjectSrcDefaultDirective[] = "object-src 'self';"; | 38 const char kObjectSrcDefaultDirective[] = "object-src 'self';"; |
| 34 const char kScriptSrcDefaultDirective[] = | 39 const char kScriptSrcDefaultDirective[] = |
| 35 "script-src 'self' chrome-extension-resource:;"; | 40 "script-src 'self' chrome-extension-resource:;"; |
| 36 | 41 |
| 42 const char kAppSandboxSubframeSrcDefaultDirective[] = "child-src 'self';"; | |
| 43 const char kAppSandboxScriptSrcDefaultDirective[] = | |
| 44 "script-src 'self' 'unsafe-inline' 'unsafe-eval';"; | |
| 45 | |
| 37 const char kSandboxDirectiveName[] = "sandbox"; | 46 const char kSandboxDirectiveName[] = "sandbox"; |
| 38 const char kAllowSameOriginToken[] = "allow-same-origin"; | 47 const char kAllowSameOriginToken[] = "allow-same-origin"; |
| 39 const char kAllowTopNavigation[] = "allow-top-navigation"; | 48 const char kAllowTopNavigation[] = "allow-top-navigation"; |
| 40 | 49 |
| 41 // This is the list of plugin types which are fully sandboxed and are safe to | 50 // This is the list of plugin types which are fully sandboxed and are safe to |
| 42 // load up in an extension, regardless of the URL they are navigated to. | 51 // load up in an extension, regardless of the URL they are navigated to. |
| 43 const char* const kSandboxedPluginTypes[] = { | 52 const char* const kSandboxedPluginTypes[] = { |
| 44 "application/pdf", | 53 "application/pdf", |
| 45 "application/x-google-chrome-pdf", | 54 "application/x-google-chrome-pdf", |
| 46 "application/x-pnacl" | 55 "application/x-pnacl" |
| 47 }; | 56 }; |
| 48 | 57 |
| 49 // List of CSP hash-source prefixes that are accepted. Blink is a bit more | 58 // List of CSP hash-source prefixes that are accepted. Blink is a bit more |
| 50 // lenient, but we only accept standard hashes to be forward-compatible. | 59 // lenient, but we only accept standard hashes to be forward-compatible. |
| 51 // http://www.w3.org/TR/2015/CR-CSP2-20150721/#hash_algo | 60 // http://www.w3.org/TR/2015/CR-CSP2-20150721/#hash_algo |
| 52 const char* const kHashSourcePrefixes[] = { | 61 const char* const kHashSourcePrefixes[] = { |
| 53 "'sha256-", | 62 "'sha256-", |
| 54 "'sha384-", | 63 "'sha384-", |
| 55 "'sha512-" | 64 "'sha512-" |
| 56 }; | 65 }; |
| 57 | 66 |
| 58 struct DirectiveStatus { | 67 class DirectiveStatus { |
| 59 explicit DirectiveStatus(const char* name) | 68 public: |
| 60 : directive_name(name), seen_in_policy(false) {} | 69 DirectiveStatus(const char* name) { directive_names_.push_back(name); } |
| 70 // Subframe related directives can have multiple directive names: "child-src" | |
| 71 // or "frame-src". | |
| 72 DirectiveStatus(const char* name1, const char* name2) { | |
| 73 directive_names_.push_back(name1); | |
| 74 directive_names_.push_back(name2); | |
| 75 } | |
| 76 bool Matches(const std::string& directive_name) const { | |
| 77 for (const auto& directive : directive_names_) { | |
| 78 if (directive_name == directive) | |
| 79 return true; | |
| 80 } | |
| 81 return false; | |
| 82 } | |
| 83 bool seen_in_policy() const { return seen_in_policy_; } | |
| 84 void set_seen_in_policy() { seen_in_policy_ = true; } | |
| 61 | 85 |
| 62 const char* directive_name; | 86 std::string name() const { |
| 63 bool seen_in_policy; | 87 DCHECK(!directive_names_.empty()); |
| 88 return directive_names_[0]; | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 std::vector<const char*> directive_names_; | |
| 93 bool seen_in_policy_ = false; | |
| 64 }; | 94 }; |
| 65 | 95 |
| 66 // Returns whether |url| starts with |scheme_and_separator| and does not have a | 96 // Returns whether |url| starts with |scheme_and_separator| and does not have a |
| 67 // too permissive wildcard host name. If |should_check_rcd| is true, then the | 97 // too permissive wildcard host name. If |should_check_rcd| is true, then the |
| 68 // Public suffix list is used to exclude wildcard TLDs such as "https://*.org". | 98 // Public suffix list is used to exclude wildcard TLDs such as "https://*.org". |
| 69 bool isNonWildcardTLD(const std::string& url, | 99 bool isNonWildcardTLD(const std::string& url, |
| 70 const std::string& scheme_and_separator, | 100 const std::string& scheme_and_separator, |
| 71 bool should_check_rcd) { | 101 bool should_check_rcd) { |
| 72 if (!base::StartsWith(url, scheme_and_separator, | 102 if (!base::StartsWith(url, scheme_and_separator, |
| 73 base::CompareCase::SENSITIVE)) | 103 base::CompareCase::SENSITIVE)) |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 manifest_errors::kInvalidCSPInsecureValue, source_literal, | 222 manifest_errors::kInvalidCSPInsecureValue, source_literal, |
| 193 directive_name))); | 223 directive_name))); |
| 194 } | 224 } |
| 195 } | 225 } |
| 196 // End of CSP directive that was started at the beginning of this method. If | 226 // End of CSP directive that was started at the beginning of this method. If |
| 197 // none of the values are secure, the policy will be empty and default to | 227 // none of the values are secure, the policy will be empty and default to |
| 198 // 'none', which is secure. | 228 // 'none', which is secure. |
| 199 sane_csp_parts->back().push_back(';'); | 229 sane_csp_parts->back().push_back(';'); |
| 200 } | 230 } |
| 201 | 231 |
| 202 // Returns true if |directive_name| matches |status.directive_name|. | |
| 203 bool UpdateStatus(const std::string& directive_name, | |
| 204 base::StringTokenizer* tokenizer, | |
| 205 DirectiveStatus* status, | |
| 206 int options, | |
| 207 std::vector<std::string>* sane_csp_parts, | |
| 208 std::vector<InstallWarning>* warnings) { | |
| 209 if (directive_name != status->directive_name) | |
| 210 return false; | |
| 211 | |
| 212 if (!status->seen_in_policy) { | |
| 213 status->seen_in_policy = true; | |
| 214 GetSecureDirectiveValues(directive_name, tokenizer, options, sane_csp_parts, | |
| 215 warnings); | |
| 216 } else { | |
| 217 // Don't show any errors for duplicate CSP directives, because it will be | |
| 218 // ignored by the CSP parser (http://www.w3.org/TR/CSP2/#policy-parsing). | |
| 219 GetSecureDirectiveValues(directive_name, tokenizer, options, sane_csp_parts, | |
| 220 NULL); | |
| 221 } | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 // Returns true if the |plugin_type| is one of the fully sandboxed plugin types. | 232 // Returns true if the |plugin_type| is one of the fully sandboxed plugin types. |
| 226 bool PluginTypeAllowed(const std::string& plugin_type) { | 233 bool PluginTypeAllowed(const std::string& plugin_type) { |
| 227 for (size_t i = 0; i < arraysize(kSandboxedPluginTypes); ++i) { | 234 for (size_t i = 0; i < arraysize(kSandboxedPluginTypes); ++i) { |
| 228 if (plugin_type == kSandboxedPluginTypes[i]) | 235 if (plugin_type == kSandboxedPluginTypes[i]) |
| 229 return true; | 236 return true; |
| 230 } | 237 } |
| 231 return false; | 238 return false; |
| 232 } | 239 } |
| 233 | 240 |
| 234 // Returns true if the policy is allowed to contain an insecure object-src | 241 // Returns true if the policy is allowed to contain an insecure object-src |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 252 if (!PluginTypeAllowed(tokenizer.token())) | 259 if (!PluginTypeAllowed(tokenizer.token())) |
| 253 return false; | 260 return false; |
| 254 } | 261 } |
| 255 // All listed plugin types are whitelisted. | 262 // All listed plugin types are whitelisted. |
| 256 return true; | 263 return true; |
| 257 } | 264 } |
| 258 // plugin-types not specified. | 265 // plugin-types not specified. |
| 259 return false; | 266 return false; |
| 260 } | 267 } |
| 261 | 268 |
| 269 class CSPEnforcer { | |
| 270 public: | |
| 271 CSPEnforcer(bool show_missing_csp_warnings) | |
| 272 : show_missing_csp_warnings_(show_missing_csp_warnings) {} | |
| 273 virtual ~CSPEnforcer() {} | |
| 274 | |
| 275 std::string Enforce(const std::string& policy, | |
| 276 std::vector<InstallWarning>* warnings); | |
| 277 | |
| 278 protected: | |
| 279 virtual std::string GetDefaultCSPValue(const DirectiveStatus& status) = 0; | |
| 280 | |
| 281 // Updates the status of a directive |directive_status| with given information | |
| 282 // about a directive token. The directive token has name |directive_name| and | |
| 283 // its values are in |tokenizer|. | |
| 284 // | |
| 285 // Returns true if |directive_status| matches |directive_name|. | |
| 286 virtual bool VisitAndEnforce(const std::string& directive_name, | |
| 287 DirectiveStatus* directive_status, | |
| 288 base::StringTokenizer* tokenizer, | |
| 289 std::vector<InstallWarning>* warnings) = 0; | |
| 290 | |
| 291 std::vector<DirectiveStatus> directives_; | |
| 292 std::vector<std::string> enforced_csp_parts_; | |
| 293 const bool show_missing_csp_warnings_; | |
| 294 }; | |
| 295 | |
| 296 std::string CSPEnforcer::Enforce(const std::string& policy, | |
| 297 std::vector<InstallWarning>* warnings) { | |
|
Devlin
2016/12/15 00:04:11
As discussed briefly offline, I still find this pr
lazyboy
2016/12/15 08:02:35
I think there are too many cases to consider here
| |
| 298 enforced_csp_parts_.clear(); | |
| 299 | |
| 300 // If any directive that we care about isn't explicitly listed in |policy|, | |
| 301 // "default-src" fallback is used. | |
| 302 DirectiveStatus default_src_status(kDefaultSrc); | |
| 303 std::vector<InstallWarning> default_src_csp_warnings; | |
| 304 | |
| 305 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. | |
| 306 for (const std::string& directive : base::SplitString( | |
| 307 policy, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { | |
| 308 base::StringTokenizer tokenizer(directive, " \t\r\n"); | |
| 309 if (!tokenizer.GetNext()) | |
| 310 continue; | |
| 311 | |
| 312 std::string directive_name = base::ToLowerASCII(tokenizer.token_piece()); | |
| 313 bool matches_enforcing_directive = false; | |
| 314 for (auto& directive_status : directives_) { | |
| 315 if (VisitAndEnforce(directive_name, &directive_status, &tokenizer, | |
| 316 warnings)) { | |
| 317 matches_enforcing_directive = true; | |
| 318 break; | |
| 319 } | |
| 320 } | |
| 321 if (matches_enforcing_directive) | |
| 322 continue; | |
| 323 | |
| 324 if (VisitAndEnforce(directive_name, &default_src_status, &tokenizer, | |
| 325 &default_src_csp_warnings)) { | |
| 326 continue; | |
| 327 } | |
| 328 | |
| 329 // Keep this directive as is. | |
| 330 enforced_csp_parts_.push_back(directive + kDirectiveSeparator); | |
| 331 } | |
| 332 | |
| 333 if (default_src_status.seen_in_policy()) { | |
| 334 for (const DirectiveStatus& directive_status : directives_) { | |
| 335 if (!directive_status.seen_in_policy()) { | |
| 336 // This |directive_status| falls back to "default-src". So warnings from | |
| 337 // "default-src" will apply. | |
| 338 if (warnings) { | |
| 339 warnings->insert(warnings->end(), default_src_csp_warnings.begin(), | |
| 340 default_src_csp_warnings.end()); | |
| 341 } | |
| 342 break; | |
| 343 } | |
| 344 } | |
| 345 } else { | |
| 346 // Did not see "default-src". | |
| 347 // Make sure we cover all sources from |directives_|. | |
| 348 for (const DirectiveStatus& directive_status : directives_) { | |
| 349 if (directive_status.seen_in_policy()) // Already covered. | |
| 350 continue; | |
| 351 enforced_csp_parts_.push_back(GetDefaultCSPValue(directive_status)); | |
| 352 | |
| 353 if (warnings && show_missing_csp_warnings_) { | |
| 354 warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( | |
| 355 manifest_errors::kInvalidCSPMissingSecureSrc, | |
| 356 directive_status.name()))); | |
| 357 } | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 return base::JoinString(enforced_csp_parts_, " "); | |
| 362 } | |
| 363 | |
| 364 class ExtensionCSPEnforcer : public CSPEnforcer { | |
| 365 public: | |
| 366 ExtensionCSPEnforcer(bool allow_insecure_object_src, int options) | |
| 367 : CSPEnforcer(true), options_(options) { | |
| 368 directives_.push_back(DirectiveStatus(kScriptSrc)); | |
| 369 if (!allow_insecure_object_src) | |
| 370 directives_.push_back(DirectiveStatus(kObjectSrc)); | |
| 371 } | |
| 372 | |
| 373 protected: | |
| 374 bool VisitAndEnforce(const std::string& directive_name, | |
| 375 DirectiveStatus* directive_status, | |
| 376 base::StringTokenizer* tokenizer, | |
| 377 std::vector<InstallWarning>* warnings) override { | |
| 378 if (!directive_status->Matches(directive_name)) | |
| 379 return false; | |
| 380 | |
| 381 if (!directive_status->seen_in_policy()) { | |
| 382 directive_status->set_seen_in_policy(); | |
| 383 GetSecureDirectiveValues(directive_name, tokenizer, options_, | |
| 384 &enforced_csp_parts_, warnings); | |
| 385 } else { | |
| 386 // Don't show any errors for duplicate CSP directives, because it will be | |
| 387 // ignored by the CSP parser (http://www.w3.org/TR/CSP2/#policy-parsing). | |
| 388 GetSecureDirectiveValues(directive_name, tokenizer, options_, | |
| 389 &enforced_csp_parts_, nullptr); | |
| 390 } | |
| 391 return true; | |
| 392 } | |
| 393 | |
| 394 std::string GetDefaultCSPValue(const DirectiveStatus& status) override { | |
| 395 if (status.Matches(kObjectSrc)) | |
| 396 return kObjectSrcDefaultDirective; | |
| 397 DCHECK(status.Matches(kScriptSrc)); | |
| 398 return kScriptSrcDefaultDirective; | |
| 399 } | |
| 400 | |
| 401 private: | |
| 402 const int options_; | |
| 403 }; | |
| 404 | |
| 405 class AppSandboxPageCSPEnforcer : public CSPEnforcer { | |
| 406 public: | |
| 407 AppSandboxPageCSPEnforcer() : CSPEnforcer(false) { | |
| 408 directives_.push_back(DirectiveStatus(kChildSrc, kFrameSrc)); | |
| 409 directives_.push_back(DirectiveStatus(kScriptSrc)); | |
| 410 } | |
| 411 | |
| 412 protected: | |
| 413 bool VisitAndEnforce(const std::string& directive_name, | |
| 414 DirectiveStatus* directive_status, | |
| 415 base::StringTokenizer* tokenizer, | |
| 416 std::vector<InstallWarning>* warnings) override { | |
| 417 if (!directive_status->Matches(directive_name)) | |
| 418 return false; | |
| 419 | |
| 420 // Don't show any errors for duplicate CSP directives, because it will be | |
| 421 // ignored by the CSP parser (http://www.w3.org/TR/CSP2/#policy-parsing). | |
| 422 bool is_duplicate_directive = directive_status->seen_in_policy(); | |
| 423 directive_status->set_seen_in_policy(); | |
| 424 | |
| 425 enforced_csp_parts_.push_back(directive_name); | |
| 426 bool seen_self_or_none = false; | |
| 427 while (tokenizer->GetNext()) { | |
| 428 std::string source_literal = tokenizer->token(); | |
| 429 std::string source_lower = base::ToLowerASCII(source_literal); | |
| 430 | |
| 431 // Keyword directive sources are surrounded with quotes, e.g. 'self', | |
| 432 // 'sha256-...', 'unsafe-eval', 'nonce-...'. These do not specify a remote | |
| 433 // host or '*', so keep them and restrict the rest. | |
| 434 if (source_lower.size() > 1u && source_lower[0] == '\'' && | |
| 435 source_lower[source_lower.size() - 1] == '\'') { | |
| 436 if (source_lower == "'none'" || source_lower == "'self'") | |
| 437 seen_self_or_none |= true; | |
| 438 enforced_csp_parts_.push_back(source_lower); | |
| 439 } else if (warnings && !is_duplicate_directive) { | |
| 440 warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( | |
| 441 manifest_errors::kInvalidCSPInsecureValue, source_literal, | |
| 442 directive_name))); | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 if (!seen_self_or_none) | |
| 447 enforced_csp_parts_.push_back("'self'"); | |
| 448 | |
| 449 // Add ";" at the end of the directive. | |
| 450 enforced_csp_parts_.back().append(kDirectiveSeparator); | |
| 451 return true; | |
| 452 } | |
| 453 | |
| 454 std::string GetDefaultCSPValue(const DirectiveStatus& status) override { | |
| 455 if (status.Matches(kChildSrc)) | |
| 456 return kAppSandboxSubframeSrcDefaultDirective; | |
| 457 DCHECK(status.Matches(kScriptSrc)); | |
| 458 return kAppSandboxScriptSrcDefaultDirective; | |
| 459 } | |
| 460 }; | |
| 461 | |
| 262 } // namespace | 462 } // namespace |
| 263 | 463 |
| 264 bool ContentSecurityPolicyIsLegal(const std::string& policy) { | 464 bool ContentSecurityPolicyIsLegal(const std::string& policy) { |
| 265 // We block these characters to prevent HTTP header injection when | 465 // We block these characters to prevent HTTP header injection when |
| 266 // representing the content security policy as an HTTP header. | 466 // representing the content security policy as an HTTP header. |
| 267 const char kBadChars[] = {',', '\r', '\n', '\0'}; | 467 const char kBadChars[] = {',', '\r', '\n', '\0'}; |
| 268 | 468 |
| 269 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == | 469 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == |
| 270 std::string::npos; | 470 std::string::npos; |
| 271 } | 471 } |
| 272 | 472 |
| 273 std::string SanitizeContentSecurityPolicy( | 473 std::string SanitizeContentSecurityPolicy( |
| 274 const std::string& policy, | 474 const std::string& policy, |
| 275 int options, | 475 int options, |
| 276 std::vector<InstallWarning>* warnings) { | 476 std::vector<InstallWarning>* warnings) { |
| 277 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. | 477 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. |
| 278 std::vector<std::string> directives = base::SplitString( | 478 std::vector<std::string> directives = base::SplitString( |
| 279 policy, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | 479 policy, kDirectiveSeparator, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| 280 | |
| 281 DirectiveStatus default_src_status(kDefaultSrc); | |
| 282 DirectiveStatus script_src_status(kScriptSrc); | |
| 283 DirectiveStatus object_src_status(kObjectSrc); | |
| 284 | 480 |
| 285 bool allow_insecure_object_src = | 481 bool allow_insecure_object_src = |
| 286 AllowedToHaveInsecureObjectSrc(options, directives); | 482 AllowedToHaveInsecureObjectSrc(options, directives); |
| 287 | 483 |
| 288 std::vector<std::string> sane_csp_parts; | 484 ExtensionCSPEnforcer csp_enforcer(allow_insecure_object_src, options); |
| 289 std::vector<InstallWarning> default_src_csp_warnings; | 485 return csp_enforcer.Enforce(policy, warnings); |
| 290 for (size_t i = 0; i < directives.size(); ++i) { | 486 } |
| 291 std::string& input = directives[i]; | 487 |
| 292 base::StringTokenizer tokenizer(input, " \t\r\n"); | 488 std::string GetEffectiveSandoxedPageCSP(const std::string& policy, |
| 293 if (!tokenizer.GetNext()) | 489 std::vector<InstallWarning>* warnings) { |
| 294 continue; | 490 AppSandboxPageCSPEnforcer csp_enforcer; |
| 295 | 491 return csp_enforcer.Enforce(policy, warnings); |
| 296 std::string directive_name = base::ToLowerASCII(tokenizer.token_piece()); | |
| 297 if (UpdateStatus(directive_name, &tokenizer, &default_src_status, options, | |
| 298 &sane_csp_parts, &default_src_csp_warnings)) | |
| 299 continue; | |
| 300 if (UpdateStatus(directive_name, &tokenizer, &script_src_status, options, | |
| 301 &sane_csp_parts, warnings)) | |
| 302 continue; | |
| 303 if (!allow_insecure_object_src && | |
| 304 UpdateStatus(directive_name, &tokenizer, &object_src_status, options, | |
| 305 &sane_csp_parts, warnings)) | |
| 306 continue; | |
| 307 | |
| 308 // Pass the other CSP directives as-is without further validation. | |
| 309 sane_csp_parts.push_back(input + ";"); | |
| 310 } | |
| 311 | |
| 312 if (default_src_status.seen_in_policy) { | |
| 313 if (!script_src_status.seen_in_policy || | |
| 314 !object_src_status.seen_in_policy) { | |
| 315 // Insecure values in default-src are only relevant if either script-src | |
| 316 // or object-src is omitted. | |
| 317 if (warnings) | |
| 318 warnings->insert(warnings->end(), | |
| 319 default_src_csp_warnings.begin(), | |
| 320 default_src_csp_warnings.end()); | |
| 321 } | |
| 322 } else { | |
| 323 if (!script_src_status.seen_in_policy) { | |
| 324 sane_csp_parts.push_back(kScriptSrcDefaultDirective); | |
| 325 if (warnings) | |
| 326 warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( | |
| 327 manifest_errors::kInvalidCSPMissingSecureSrc, kScriptSrc))); | |
| 328 } | |
| 329 if (!object_src_status.seen_in_policy && !allow_insecure_object_src) { | |
| 330 sane_csp_parts.push_back(kObjectSrcDefaultDirective); | |
| 331 if (warnings) | |
| 332 warnings->push_back(CSPInstallWarning(ErrorUtils::FormatErrorMessage( | |
| 333 manifest_errors::kInvalidCSPMissingSecureSrc, kObjectSrc))); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 return base::JoinString(sane_csp_parts, " "); | |
| 338 } | 492 } |
| 339 | 493 |
| 340 bool ContentSecurityPolicyIsSandboxed( | 494 bool ContentSecurityPolicyIsSandboxed( |
| 341 const std::string& policy, Manifest::Type type) { | 495 const std::string& policy, Manifest::Type type) { |
| 342 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. | 496 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. |
| 343 bool seen_sandbox = false; | 497 bool seen_sandbox = false; |
| 344 for (const std::string& input : base::SplitString( | 498 for (const std::string& input : base::SplitString( |
| 345 policy, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { | 499 policy, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { |
| 346 base::StringTokenizer tokenizer(input, " \t\r\n"); | 500 base::StringTokenizer tokenizer(input, " \t\r\n"); |
| 347 if (!tokenizer.GetNext()) | 501 if (!tokenizer.GetNext()) |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 367 } | 521 } |
| 368 } | 522 } |
| 369 } | 523 } |
| 370 | 524 |
| 371 return seen_sandbox; | 525 return seen_sandbox; |
| 372 } | 526 } |
| 373 | 527 |
| 374 } // namespace csp_validator | 528 } // namespace csp_validator |
| 375 | 529 |
| 376 } // namespace extensions | 530 } // namespace extensions |
| OLD | NEW |