nsCSPUtils.h (26987B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsCSPUtils_h___ 8 #define nsCSPUtils_h___ 9 10 #include "mozilla/ErrorResult.h" 11 #include "nsCOMPtr.h" 12 #include "nsILoadInfo.h" 13 #include "nsIURI.h" 14 #include "nsString.h" 15 #include "nsTArray.h" 16 #include "nsUnicharUtils.h" 17 18 class nsIChannel; 19 20 namespace mozilla::dom { 21 struct CSP; 22 class Document; 23 } // namespace mozilla::dom 24 25 /* =============== Logging =================== */ 26 27 void CSP_LogLocalizedStr(const char* aName, const nsTArray<nsString>& aParams, 28 const nsACString& aSourceName, 29 const nsAString& aSourceLine, uint32_t aLineNumber, 30 uint32_t aColumnNumber, uint32_t aFlags, 31 const nsACString& aCategory, uint64_t aInnerWindowID, 32 bool aFromPrivateWindow); 33 34 void CSP_GetLocalizedStr(const char* aName, const nsTArray<nsString>& aParams, 35 nsAString& outResult); 36 37 void CSP_LogStrMessage(const nsAString& aMsg); 38 39 void CSP_LogMessage(const nsAString& aMessage, const nsACString& aSourceName, 40 const nsAString& aSourceLine, uint32_t aLineNumber, 41 uint32_t aColumnNumber, uint32_t aFlags, 42 const nsACString& aCategory, uint64_t aInnerWindowID, 43 bool aFromPrivateWindow); 44 45 /* =============== Constant and Type Definitions ================== */ 46 47 #define INLINE_STYLE_VIOLATION_OBSERVER_TOPIC \ 48 "violated base restriction: Inline Stylesheets will not apply" 49 #define INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC \ 50 "violated base restriction: Inline Scripts will not execute" 51 #define EVAL_VIOLATION_OBSERVER_TOPIC \ 52 "violated base restriction: Code will not be created from strings" 53 #define WASM_EVAL_VIOLATION_OBSERVER_TOPIC \ 54 "violated base restriction: WebAssembly code will not be created from " \ 55 "dynamically" 56 #define SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC "Inline Script had invalid nonce" 57 #define STYLE_NONCE_VIOLATION_OBSERVER_TOPIC "Inline Style had invalid nonce" 58 #define SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC "Inline Script had invalid hash" 59 #define STYLE_HASH_VIOLATION_OBSERVER_TOPIC "Inline Style had invalid hash" 60 #define TRUSTED_TYPES_VIOLATION_OBSERVER_TOPIC \ 61 "Tried to create a trusted-types policy with a forbidden policy name" 62 #define REQUIRE_TRUSTED_TYPES_FOR_SCRIPT_OBSERVER_TOPIC \ 63 "Type mismatch for injection sink" 64 65 // these strings map to the CSPDirectives in nsIContentSecurityPolicy 66 // NOTE: When implementing a new directive, you will need to add it here but 67 // also add a corresponding entry to the constants in 68 // nsIContentSecurityPolicy.idl and also create an entry for the new directive 69 // in nsCSPDirective::toDomCSPStruct() and add it to CSPDictionaries.webidl. 70 // Order of elements below important! Make sure it matches the order as in 71 // nsIContentSecurityPolicy.idl 72 static const char* CSPStrDirectives[] = { 73 "-error-", // NO_DIRECTIVE 74 "default-src", // DEFAULT_SRC_DIRECTIVE 75 "script-src", // SCRIPT_SRC_DIRECTIVE 76 "object-src", // OBJECT_SRC_DIRECTIVE 77 "style-src", // STYLE_SRC_DIRECTIVE 78 "img-src", // IMG_SRC_DIRECTIVE 79 "media-src", // MEDIA_SRC_DIRECTIVE 80 "frame-src", // FRAME_SRC_DIRECTIVE 81 "font-src", // FONT_SRC_DIRECTIVE 82 "connect-src", // CONNECT_SRC_DIRECTIVE 83 "report-uri", // REPORT_URI_DIRECTIVE 84 "frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE 85 "reflected-xss", // REFLECTED_XSS_DIRECTIVE 86 "base-uri", // BASE_URI_DIRECTIVE 87 "form-action", // FORM_ACTION_DIRECTIVE 88 "manifest-src", // MANIFEST_SRC_DIRECTIVE 89 "upgrade-insecure-requests", // UPGRADE_IF_INSECURE_DIRECTIVE 90 "child-src", // CHILD_SRC_DIRECTIVE 91 "block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT 92 "sandbox", // SANDBOX_DIRECTIVE 93 "worker-src", // WORKER_SRC_DIRECTIVE 94 "script-src-elem", // SCRIPT_SRC_ELEM_DIRECTIVE 95 "script-src-attr", // SCRIPT_SRC_ATTR_DIRECTIVE 96 "style-src-elem", // STYLE_SRC_ELEM_DIRECTIVE 97 "style-src-attr", // STYLE_SRC_ATTR_DIRECTIVE 98 "require-trusted-types-for", // REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE 99 "trusted-types", // TRUSTED_TYPES_DIRECTIVE 100 "report-to", // REPORT_TO_DIRECTIVE 101 }; 102 103 inline const char* CSP_CSPDirectiveToString(CSPDirective aDir) { 104 return CSPStrDirectives[static_cast<uint32_t>(aDir)]; 105 } 106 107 CSPDirective CSP_StringToCSPDirective(const nsAString& aDir); 108 109 #define FOR_EACH_CSP_KEYWORD(MACRO) \ 110 MACRO(CSP_SELF, "'self'") \ 111 MACRO(CSP_UNSAFE_INLINE, "'unsafe-inline'") \ 112 MACRO(CSP_UNSAFE_EVAL, "'unsafe-eval'") \ 113 MACRO(CSP_UNSAFE_HASHES, "'unsafe-hashes'") \ 114 MACRO(CSP_NONE, "'none'") \ 115 MACRO(CSP_NONCE, "'nonce-") \ 116 MACRO(CSP_REPORT_SAMPLE, "'report-sample'") \ 117 MACRO(CSP_STRICT_DYNAMIC, "'strict-dynamic'") \ 118 MACRO(CSP_WASM_UNSAFE_EVAL, "'wasm-unsafe-eval'") \ 119 MACRO(CSP_ALLOW_DUPLICATES, "'allow-duplicates'") \ 120 MACRO(CSP_TRUSTED_TYPES_EVAL, "'trusted-types-eval'") 121 122 enum CSPKeyword { 123 #define KEYWORD_ENUM(id_, string_) id_, 124 FOR_EACH_CSP_KEYWORD(KEYWORD_ENUM) 125 #undef KEYWORD_ENUM 126 127 // CSP_LAST_KEYWORD_VALUE always needs to be the last element in the enum 128 // because we use it to calculate the size for the char* array. 129 CSP_LAST_KEYWORD_VALUE, 130 131 // Putting CSP_HASH after the delimitor, because CSP_HASH is not a valid 132 // keyword (hash uses e.g. sha256, sha512) but we use CSP_HASH internally 133 // to identify allowed hashes in ::allows. 134 CSP_HASH 135 }; 136 137 // The keywords, in UTF-8 form. 138 static const char* gCSPUTF8Keywords[] = { 139 #define KEYWORD_UTF8_LITERAL(id_, string_) string_, 140 FOR_EACH_CSP_KEYWORD(KEYWORD_UTF8_LITERAL) 141 #undef KEYWORD_UTF8_LITERAL 142 }; 143 144 // The keywords, in UTF-16 form. 145 static const char16_t* gCSPUTF16Keywords[] = { 146 #define KEYWORD_UTF16_LITERAL(id_, string_) u"" string_, 147 FOR_EACH_CSP_KEYWORD(KEYWORD_UTF16_LITERAL) 148 #undef KEYWORD_UTF16_LITERAL 149 }; 150 151 #undef FOR_EACH_CSP_KEYWORD 152 153 inline const char* CSP_EnumToUTF8Keyword(enum CSPKeyword aKey) { 154 // Make sure all elements in enum CSPKeyword got added to gCSPUTF8Keywords. 155 static_assert((sizeof(gCSPUTF8Keywords) / sizeof(gCSPUTF8Keywords[0]) == 156 CSP_LAST_KEYWORD_VALUE), 157 "CSP_LAST_KEYWORD_VALUE != length(gCSPUTF8Keywords)"); 158 159 if (static_cast<uint32_t>(aKey) < 160 static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) { 161 return gCSPUTF8Keywords[static_cast<uint32_t>(aKey)]; 162 } 163 return "error: invalid keyword in CSP_EnumToUTF8Keyword"; 164 } 165 166 inline const char16_t* CSP_EnumToUTF16Keyword(enum CSPKeyword aKey) { 167 // Make sure all elements in enum CSPKeyword got added to gCSPUTF16Keywords. 168 static_assert((sizeof(gCSPUTF16Keywords) / sizeof(gCSPUTF16Keywords[0]) == 169 CSP_LAST_KEYWORD_VALUE), 170 "CSP_LAST_KEYWORD_VALUE != length(gCSPUTF16Keywords)"); 171 172 if (static_cast<uint32_t>(aKey) < 173 static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) { 174 return gCSPUTF16Keywords[static_cast<uint32_t>(aKey)]; 175 } 176 return u"error: invalid keyword in CSP_EnumToUTF16Keyword"; 177 } 178 179 inline CSPKeyword CSP_UTF16KeywordToEnum(const nsAString& aKey) { 180 nsString lowerKey = PromiseFlatString(aKey); 181 ToLowerCase(lowerKey); 182 183 for (uint32_t i = 0; i < CSP_LAST_KEYWORD_VALUE; i++) { 184 if (lowerKey.Equals(gCSPUTF16Keywords[i])) { 185 return static_cast<CSPKeyword>(i); 186 } 187 } 188 NS_ASSERTION(false, "Can not convert unknown Keyword to Enum"); 189 return CSP_LAST_KEYWORD_VALUE; 190 } 191 192 nsresult CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp, 193 const nsAString& aHeaderValue, 194 bool aReportOnly); 195 196 /* =============== Helpers ================== */ 197 198 already_AddRefed<nsIContentSecurityPolicy> CSP_CreateFromHeader( 199 const nsAString& aHeaderValue, nsIURI* aSelfURI, 200 nsIPrincipal* aLoadingPrincipal, mozilla::ErrorResult& aRv); 201 202 class nsCSPHostSrc; 203 204 nsCSPHostSrc* CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI); 205 bool CSP_IsEmptyDirective(const nsAString& aValue, const nsAString& aDir); 206 bool CSP_IsInvalidDirectiveValue(mozilla::Span<const char16_t> aValue); 207 bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir); 208 bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey); 209 bool CSP_IsQuotelessKeyword(const nsAString& aKey); 210 CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType); 211 212 class nsCSPSrcVisitor; 213 214 void CSP_PercentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr); 215 bool CSP_ShouldResponseInheritCSP(nsIChannel* aChannel); 216 bool CSP_ShouldURIInheritCSP(nsIURI* aURI); 217 218 void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, 219 const nsAString& aPolicyStr); 220 221 // Checks if the URI is "chrome://browser/content/browser.xhtml" 222 bool CSP_IsBrowserXHTML(nsIURI* aURI); 223 224 /* =============== nsCSPSrc ================== */ 225 226 class nsCSPBaseSrc { 227 public: 228 nsCSPBaseSrc(); 229 virtual ~nsCSPBaseSrc(); 230 231 virtual bool permits(nsIURI* aUri, bool aWasRedirected, bool aReportOnly, 232 bool aUpgradeInsecure) const; 233 virtual bool allows(enum CSPKeyword aKeyword, 234 const nsAString& aHashOrNonce) const; 235 virtual bool visit(nsCSPSrcVisitor* aVisitor) const = 0; 236 virtual void toString(nsAString& outStr) const = 0; 237 238 virtual bool isReportSample() const { return false; } 239 240 virtual bool isHash() const { return false; } 241 virtual bool isNonce() const { return false; } 242 virtual bool isKeyword(CSPKeyword aKeyword) const { return false; } 243 virtual bool isTrustedTypesDirectivePolicyName() const { return false; } 244 }; 245 246 /* =============== nsCSPSchemeSrc ============ */ 247 248 class nsCSPSchemeSrc : public nsCSPBaseSrc { 249 public: 250 explicit nsCSPSchemeSrc(const nsAString& aScheme); 251 virtual ~nsCSPSchemeSrc(); 252 253 bool permits(nsIURI* aUri, bool aWasRedirected, bool aReportOnly, 254 bool aUpgradeInsecure) const override; 255 bool visit(nsCSPSrcVisitor* aVisitor) const override; 256 void toString(nsAString& outStr) const override; 257 258 inline void getScheme(nsAString& outStr) const { outStr.Assign(mScheme); }; 259 260 private: 261 nsString mScheme; 262 }; 263 264 /* =============== nsCSPHostSrc ============== */ 265 266 class nsCSPHostSrc : public nsCSPBaseSrc { 267 public: 268 explicit nsCSPHostSrc(const nsAString& aHost); 269 virtual ~nsCSPHostSrc(); 270 271 bool permits(nsIURI* aUri, bool aWasRedirected, bool aReportOnly, 272 bool aUpgradeInsecure) const override; 273 bool visit(nsCSPSrcVisitor* aVisitor) const override; 274 void toString(nsAString& outStr) const override; 275 276 void setScheme(const nsAString& aScheme); 277 void setPort(const nsAString& aPort); 278 void appendPath(const nsAString& aPath); 279 280 inline void setGeneratedFromSelfKeyword() const { 281 mGeneratedFromSelfKeyword = true; 282 } 283 284 inline void setIsUniqueOrigin() const { mIsUniqueOrigin = true; } 285 286 inline void setWithinFrameAncestorsDir(bool aValue) const { 287 mWithinFrameAncstorsDir = aValue; 288 } 289 290 inline void getScheme(nsAString& outStr) const { outStr.Assign(mScheme); }; 291 292 inline void getHost(nsAString& outStr) const { outStr.Assign(mHost); }; 293 294 inline void getPort(nsAString& outStr) const { outStr.Assign(mPort); }; 295 296 inline void getPath(nsAString& outStr) const { outStr.Assign(mPath); }; 297 298 private: 299 nsString mScheme; 300 nsString mHost; 301 nsString mPort; 302 nsString mPath; 303 mutable bool mGeneratedFromSelfKeyword; 304 mutable bool mIsUniqueOrigin; 305 mutable bool mWithinFrameAncstorsDir; 306 }; 307 308 /* =============== nsCSPKeywordSrc ============ */ 309 310 class nsCSPKeywordSrc : public nsCSPBaseSrc { 311 public: 312 explicit nsCSPKeywordSrc(CSPKeyword aKeyword); 313 virtual ~nsCSPKeywordSrc(); 314 315 bool allows(enum CSPKeyword aKeyword, 316 const nsAString& aHashOrNonce) const override; 317 bool visit(nsCSPSrcVisitor* aVisitor) const override; 318 void toString(nsAString& outStr) const override; 319 320 inline CSPKeyword getKeyword() const { return mKeyword; }; 321 322 bool isReportSample() const override { return mKeyword == CSP_REPORT_SAMPLE; } 323 324 bool isKeyword(CSPKeyword aKeyword) const final { 325 return mKeyword == aKeyword; 326 } 327 328 private: 329 CSPKeyword mKeyword; 330 }; 331 332 /* =============== nsCSPNonceSource =========== */ 333 334 class nsCSPNonceSrc : public nsCSPBaseSrc { 335 public: 336 explicit nsCSPNonceSrc(const nsAString& aNonce); 337 virtual ~nsCSPNonceSrc(); 338 339 bool allows(enum CSPKeyword aKeyword, 340 const nsAString& aHashOrNonce) const override; 341 bool visit(nsCSPSrcVisitor* aVisitor) const override; 342 void toString(nsAString& outStr) const override; 343 344 inline void getNonce(nsAString& outStr) const { outStr.Assign(mNonce); }; 345 346 bool isNonce() const final { return true; } 347 348 private: 349 nsString mNonce; 350 }; 351 352 /* =============== nsCSPHashSource ============ */ 353 354 class nsCSPHashSrc : public nsCSPBaseSrc { 355 public: 356 nsCSPHashSrc(const nsAString& algo, const nsAString& hash); 357 virtual ~nsCSPHashSrc(); 358 359 bool allows(enum CSPKeyword aKeyword, 360 const nsAString& aHashOrNonce) const override; 361 void toString(nsAString& outStr) const override; 362 bool visit(nsCSPSrcVisitor* aVisitor) const override; 363 364 inline void getAlgorithm(nsAString& outStr) const { 365 outStr.Assign(mAlgorithm); 366 }; 367 368 inline void getHash(nsAString& outStr) const { outStr.Assign(mHash); }; 369 370 bool isHash() const final { return true; } 371 372 private: 373 nsString mAlgorithm; 374 nsString mHash; 375 }; 376 377 /* =============== nsCSPReportURI ============ */ 378 379 class nsCSPReportURI : public nsCSPBaseSrc { 380 public: 381 explicit nsCSPReportURI(nsIURI* aURI); 382 virtual ~nsCSPReportURI(); 383 384 bool visit(nsCSPSrcVisitor* aVisitor) const override; 385 void toString(nsAString& outStr) const override; 386 387 private: 388 nsCOMPtr<nsIURI> mReportURI; 389 }; 390 391 /* =============== nsCSPGroup ============ */ 392 393 class nsCSPGroup : public nsCSPBaseSrc { 394 public: 395 explicit nsCSPGroup(const nsAString& aGroup); 396 virtual ~nsCSPGroup(); 397 398 bool visit(nsCSPSrcVisitor* aVisitor) const override; 399 void toString(nsAString& aOutStr) const override; 400 401 private: 402 nsString mGroup; 403 }; 404 405 /* =============== nsCSPSandboxFlags ================== */ 406 407 class nsCSPSandboxFlags : public nsCSPBaseSrc { 408 public: 409 explicit nsCSPSandboxFlags(const nsAString& aFlags); 410 virtual ~nsCSPSandboxFlags(); 411 412 bool visit(nsCSPSrcVisitor* aVisitor) const override; 413 void toString(nsAString& outStr) const override; 414 415 private: 416 nsString mFlags; 417 }; 418 419 /* =============== nsCSPRequireTrustedTypesForDirectiveValue =============== */ 420 421 class nsCSPRequireTrustedTypesForDirectiveValue : public nsCSPBaseSrc { 422 public: 423 explicit nsCSPRequireTrustedTypesForDirectiveValue(const nsAString& aValue); 424 virtual ~nsCSPRequireTrustedTypesForDirectiveValue() = default; 425 426 bool visit(nsCSPSrcVisitor* aVisitor) const override; 427 void toString(nsAString& aOutStr) const override; 428 429 private: 430 const nsString mValue; 431 }; 432 433 /* =============== nsCSPTrustedTypesDirectiveExpression =============== */ 434 435 class nsCSPTrustedTypesDirectivePolicyName : public nsCSPBaseSrc { 436 public: 437 explicit nsCSPTrustedTypesDirectivePolicyName(const nsAString& aName); 438 virtual ~nsCSPTrustedTypesDirectivePolicyName() = default; 439 440 bool visit(nsCSPSrcVisitor* aVisitor) const override; 441 void toString(nsAString& aOutStr) const override; 442 443 bool isTrustedTypesDirectivePolicyName() const override { return true; } 444 445 const nsString& GetName() const { return mName; } 446 447 private: 448 const nsString mName; 449 }; 450 451 class nsCSPTrustedTypesDirectiveInvalidToken : public nsCSPBaseSrc { 452 public: 453 explicit nsCSPTrustedTypesDirectiveInvalidToken( 454 const nsAString& aInvalidToken); 455 virtual ~nsCSPTrustedTypesDirectiveInvalidToken() = default; 456 457 bool visit(nsCSPSrcVisitor* aVisitor) const override; 458 void toString(nsAString& aOutStr) const override; 459 460 private: 461 const nsString mInvalidToken; 462 }; 463 464 /* =============== nsCSPSrcVisitor ================== */ 465 466 class nsCSPSrcVisitor { 467 public: 468 virtual bool visitSchemeSrc(const nsCSPSchemeSrc& src) = 0; 469 470 virtual bool visitHostSrc(const nsCSPHostSrc& src) = 0; 471 472 virtual bool visitKeywordSrc(const nsCSPKeywordSrc& src) = 0; 473 474 virtual bool visitNonceSrc(const nsCSPNonceSrc& src) = 0; 475 476 virtual bool visitHashSrc(const nsCSPHashSrc& src) = 0; 477 478 protected: 479 explicit nsCSPSrcVisitor() = default; 480 virtual ~nsCSPSrcVisitor() = default; 481 }; 482 483 /* =============== nsCSPDirective ============= */ 484 485 class nsCSPDirective { 486 public: 487 explicit nsCSPDirective(CSPDirective aDirective); 488 virtual ~nsCSPDirective(); 489 490 virtual bool permits(CSPDirective aDirective, nsILoadInfo* aLoadInfo, 491 nsIURI* aUri, bool aWasRedirected, bool aReportOnly, 492 bool aUpgradeInsecure) const; 493 virtual bool allows(enum CSPKeyword aKeyword, 494 const nsAString& aHashOrNonce) const; 495 bool allowsAllInlineBehavior(CSPDirective aDir) const; 496 497 // Implements step 2.1 to 2.7 of 498 // <https://w3c.github.io/trusted-types/dist/spec/#should-block-create-policy>. 499 bool ShouldCreateViolationForNewTrustedTypesPolicy( 500 const nsAString& aPolicyName, 501 const nsTArray<nsString>& aCreatedPolicyNames) const; 502 503 // Implements step 2.1 to 2.4 of 504 // <https://w3c.github.io/trusted-types/dist/spec/#abstract-opdef-does-sink-type-require-trusted-types>. 505 bool AreTrustedTypesForSinkGroupRequired(const nsAString& aSinkGroup) const; 506 507 virtual void toString(nsAString& outStr) const; 508 void toDomCSPStruct(mozilla::dom::CSP& outCSP) const; 509 510 // Takes ownership of the passed sources. 511 virtual void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) { 512 mSrcs = aSrcs.Clone(); 513 } 514 515 bool isDefaultDirective() const; 516 517 virtual bool equals(CSPDirective aDirective) const; 518 519 void getReportURIs(nsTArray<nsString>& outReportURIs) const; 520 521 void getReportGroup(nsAString& outReportGroup) const; 522 523 bool visitSrcs(nsCSPSrcVisitor* aVisitor) const; 524 525 virtual void getDirName(nsAString& outStr) const; 526 527 bool hasReportSampleKeyword() const; 528 529 private: 530 bool ContainsTrustedTypesDirectivePolicyName( 531 const nsAString& aPolicyName) const; 532 533 protected: 534 CSPDirective mDirective; 535 nsTArray<nsCSPBaseSrc*> mSrcs; 536 }; 537 538 /* =============== nsCSPChildSrcDirective ============= */ 539 540 /* 541 * In CSP 3 child-src is deprecated. For backwards compatibility 542 * child-src needs to restrict: 543 * (*) frames, in case frame-src is not expicitly specified 544 * (*) workers, in case worker-src is not expicitly specified 545 */ 546 class nsCSPChildSrcDirective : public nsCSPDirective { 547 public: 548 explicit nsCSPChildSrcDirective(CSPDirective aDirective); 549 virtual ~nsCSPChildSrcDirective(); 550 551 void setRestrictFrames() { mRestrictFrames = true; } 552 553 void setRestrictWorkers() { mRestrictWorkers = true; } 554 555 virtual bool equals(CSPDirective aDirective) const override; 556 557 private: 558 bool mRestrictFrames; 559 bool mRestrictWorkers; 560 }; 561 562 /* =============== nsCSPScriptSrcDirective ============= */ 563 564 /* 565 * In CSP 3 worker-src restricts workers, for backwards compatibily 566 * script-src has to restrict workers as the ultimate fallback if 567 * neither worker-src nor child-src is present in a CSP. 568 */ 569 class nsCSPScriptSrcDirective : public nsCSPDirective { 570 public: 571 explicit nsCSPScriptSrcDirective(CSPDirective aDirective); 572 virtual ~nsCSPScriptSrcDirective(); 573 574 void setRestrictWorkers() { mRestrictWorkers = true; } 575 void setRestrictScriptElem() { mRestrictScriptElem = true; } 576 void setRestrictScriptAttr() { mRestrictScriptAttr = true; } 577 578 bool equals(CSPDirective aDirective) const override; 579 580 private: 581 bool mRestrictWorkers = false; 582 bool mRestrictScriptElem = false; 583 bool mRestrictScriptAttr = false; 584 }; 585 586 /* =============== nsCSPStyleSrcDirective ============= */ 587 588 /* 589 * In CSP 3 style-src is use as a fallback for style-src-elem and 590 * style-src-attr. 591 */ 592 class nsCSPStyleSrcDirective : public nsCSPDirective { 593 public: 594 explicit nsCSPStyleSrcDirective(CSPDirective aDirective); 595 virtual ~nsCSPStyleSrcDirective(); 596 597 void setRestrictStyleElem() { mRestrictStyleElem = true; } 598 void setRestrictStyleAttr() { mRestrictStyleAttr = true; } 599 600 bool equals(CSPDirective aDirective) const override; 601 602 private: 603 bool mRestrictStyleElem = false; 604 bool mRestrictStyleAttr = false; 605 }; 606 607 /* =============== nsBlockAllMixedContentDirective === */ 608 609 class nsBlockAllMixedContentDirective : public nsCSPDirective { 610 public: 611 explicit nsBlockAllMixedContentDirective(CSPDirective aDirective); 612 ~nsBlockAllMixedContentDirective(); 613 614 bool permits(CSPDirective aDirective, nsILoadInfo* aLoadInfo, nsIURI* aUri, 615 bool aWasRedirected, bool aReportOnly, 616 bool aUpgradeInsecure) const override { 617 return false; 618 } 619 620 bool permits(nsIURI* aUri) const { return false; } 621 622 bool allows(enum CSPKeyword aKeyword, 623 const nsAString& aHashOrNonce) const override { 624 return false; 625 } 626 627 void toString(nsAString& outStr) const override; 628 629 void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) override { 630 MOZ_ASSERT(false, "block-all-mixed-content does not hold any srcs"); 631 } 632 633 void getDirName(nsAString& outStr) const override; 634 }; 635 636 /* =============== nsUpgradeInsecureDirective === */ 637 638 /* 639 * Upgrading insecure requests includes the following actors: 640 * (1) CSP: 641 * The CSP implementation allowlists the http-request 642 * in case the policy is executed in enforcement mode. 643 * The CSP implementation however does not allow http 644 * requests to succeed if executed in report-only mode. 645 * In such a case the CSP implementation reports the 646 * error back to the page. 647 * 648 * (2) MixedContent: 649 * The evalution of MixedContent allowlists all http 650 * requests with the promise that the http requests 651 * gets upgraded to https before any data is fetched 652 * from the network. 653 * 654 * (3) CORS: 655 * Does not consider the http request to be of a 656 * different origin in case the scheme is the only 657 * difference in otherwise matching URIs. 658 * 659 * (4) nsHttpChannel: 660 * Before connecting, the channel gets redirected 661 * to use https. 662 * 663 * (5) WebSocketChannel: 664 * Similar to the httpChannel, the websocketchannel 665 * gets upgraded from ws to wss. 666 */ 667 class nsUpgradeInsecureDirective : public nsCSPDirective { 668 public: 669 explicit nsUpgradeInsecureDirective(CSPDirective aDirective); 670 ~nsUpgradeInsecureDirective(); 671 672 bool permits(CSPDirective aDirective, nsILoadInfo* aLoadInfo, nsIURI* aUri, 673 bool aWasRedirected, bool aReportOnly, 674 bool aUpgradeInsecure) const override { 675 return false; 676 } 677 678 bool permits(nsIURI* aUri) const { return false; } 679 680 bool allows(enum CSPKeyword aKeyword, 681 const nsAString& aHashOrNonce) const override { 682 return false; 683 } 684 685 void toString(nsAString& outStr) const override; 686 687 void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) override { 688 MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); 689 } 690 691 void getDirName(nsAString& outStr) const override; 692 }; 693 694 /* =============== nsCSPPolicy ================== */ 695 696 class nsCSPPolicy { 697 public: 698 nsCSPPolicy(); 699 virtual ~nsCSPPolicy(); 700 701 bool permits(CSPDirective aDirective, nsILoadInfo* aLoadInfo, nsIURI* aUri, 702 bool aWasRedirected, bool aSpecific, 703 nsAString& outViolatedDirective, 704 nsAString& outViolatedDirectiveString) const; 705 bool allows(CSPDirective aDirective, enum CSPKeyword aKeyword, 706 const nsAString& aHashOrNonce) const; 707 void toString(nsAString& outStr) const; 708 void toDomCSPStruct(mozilla::dom::CSP& outCSP) const; 709 710 inline void addDirective(nsCSPDirective* aDir) { 711 if (aDir->equals( 712 nsIContentSecurityPolicy::REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE)) { 713 mHasRequireTrustedTypesForDirective = true; 714 } 715 mDirectives.AppendElement(aDir); 716 } 717 718 inline void addUpgradeInsecDir(nsUpgradeInsecureDirective* aDir) { 719 mUpgradeInsecDir = aDir; 720 addDirective(aDir); 721 } 722 723 bool hasDirective(CSPDirective aDir) const; 724 725 inline void setDeliveredViaMetaTagFlag(bool aFlag) { 726 mDeliveredViaMetaTag = aFlag; 727 } 728 729 inline bool getDeliveredViaMetaTagFlag() const { 730 return mDeliveredViaMetaTag; 731 } 732 733 inline bool hasRequireTrustedTypesForDirective() const { 734 return mHasRequireTrustedTypesForDirective; 735 } 736 737 inline void setReportOnlyFlag(bool aFlag) { mReportOnly = aFlag; } 738 739 // Related to https://w3c.github.io/webappsec-csp/#policy-disposition. 740 // @return true if disposition is "report", false otherwise. 741 inline bool getReportOnlyFlag() const { return mReportOnly; } 742 743 enum class Disposition { Enforce, Report }; 744 745 Disposition getDisposition() const { 746 return getReportOnlyFlag() ? Disposition::Report : Disposition::Enforce; 747 } 748 749 void getReportURIs(nsTArray<nsString>& outReportURIs) const; 750 751 void getReportGroup(nsAString& outReportGroup) const; 752 753 void getViolatedDirectiveInformation(CSPDirective aDirective, 754 nsAString& aDirectiveName, 755 nsAString& aDirectiveNameAndValue, 756 bool* aReportSample) const; 757 758 uint32_t getSandboxFlags() const; 759 760 inline uint32_t getNumDirectives() const { return mDirectives.Length(); } 761 762 void getDirectiveNames(nsTArray<nsString>& outDirectives) const; 763 764 bool visitDirectiveSrcs(CSPDirective aDir, nsCSPSrcVisitor* aVisitor) const; 765 766 bool allowsAllInlineBehavior(CSPDirective aDir) const; 767 768 /* 769 * Implements step 2.1 to 2.7 of 770 * <https://w3c.github.io/trusted-types/dist/spec/#should-block-create-policy>. 771 * and returns the result of "createViolation". 772 * 773 * @param aCreatedPolicyNames The already created policy names. 774 * @return true if a violation for aPolicyName should be created. 775 */ 776 bool ShouldCreateViolationForNewTrustedTypesPolicy( 777 const nsAString& aPolicyName, 778 const nsTArray<nsString>& aCreatedPolicyNames) const; 779 780 /** 781 * Implements step 2.1 to 2.4 of 782 * <https://w3c.github.io/trusted-types/dist/spec/#abstract-opdef-does-sink-type-require-trusted-types>. 783 */ 784 bool AreTrustedTypesForSinkGroupRequired(const nsAString& aSinkGroup) const; 785 786 private: 787 nsCSPDirective* matchingOrDefaultDirective(CSPDirective aDirective) const; 788 789 nsUpgradeInsecureDirective* mUpgradeInsecDir; 790 nsTArray<nsCSPDirective*> mDirectives; 791 bool mHasRequireTrustedTypesForDirective = false; 792 bool mReportOnly; 793 bool mDeliveredViaMetaTag; 794 }; 795 796 #endif /* nsCSPUtils_h___ */