diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /dom/security/nsCSPUtils.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/security/nsCSPUtils.h')
-rw-r--r-- | dom/security/nsCSPUtils.h | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h new file mode 100644 index 0000000000..dd3ea9a1c4 --- /dev/null +++ b/dom/security/nsCSPUtils.h @@ -0,0 +1,699 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsCSPUtils_h___ +#define nsCSPUtils_h___ + +#include "nsCOMPtr.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIURI.h" +#include "nsLiteralString.h" +#include "nsString.h" +#include "nsTArray.h" +#include "nsUnicharUtils.h" +#include "mozilla/Logging.h" + +class nsIChannel; + +namespace mozilla::dom { +struct CSP; +class Document; +} // namespace mozilla::dom + +/* =============== Logging =================== */ + +void CSP_LogLocalizedStr(const char* aName, const nsTArray<nsString>& aParams, + const nsAString& aSourceName, + const nsAString& aSourceLine, uint32_t aLineNumber, + uint32_t aColumnNumber, uint32_t aFlags, + const nsACString& aCategory, uint64_t aInnerWindowID, + bool aFromPrivateWindow); + +void CSP_GetLocalizedStr(const char* aName, const nsTArray<nsString>& aParams, + nsAString& outResult); + +void CSP_LogStrMessage(const nsAString& aMsg); + +void CSP_LogMessage(const nsAString& aMessage, const nsAString& aSourceName, + const nsAString& aSourceLine, uint32_t aLineNumber, + uint32_t aColumnNumber, uint32_t aFlags, + const nsACString& aCategory, uint64_t aInnerWindowID, + bool aFromPrivateWindow); + +/* =============== Constant and Type Definitions ================== */ + +#define INLINE_STYLE_VIOLATION_OBSERVER_TOPIC \ + "violated base restriction: Inline Stylesheets will not apply" +#define INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC \ + "violated base restriction: Inline Scripts will not execute" +#define EVAL_VIOLATION_OBSERVER_TOPIC \ + "violated base restriction: Code will not be created from strings" +#define WASM_EVAL_VIOLATION_OBSERVER_TOPIC \ + "violated base restriction: WebAssembly code will not be created from " \ + "dynamically" +#define SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC "Inline Script had invalid nonce" +#define STYLE_NONCE_VIOLATION_OBSERVER_TOPIC "Inline Style had invalid nonce" +#define SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC "Inline Script had invalid hash" +#define STYLE_HASH_VIOLATION_OBSERVER_TOPIC "Inline Style had invalid hash" + +// these strings map to the CSPDirectives in nsIContentSecurityPolicy +// NOTE: When implementing a new directive, you will need to add it here but +// also add a corresponding entry to the constants in +// nsIContentSecurityPolicy.idl and also create an entry for the new directive +// in nsCSPDirective::toDomCSPStruct() and add it to CSPDictionaries.webidl. +// Order of elements below important! Make sure it matches the order as in +// nsIContentSecurityPolicy.idl +static const char* CSPStrDirectives[] = { + "-error-", // NO_DIRECTIVE + "default-src", // DEFAULT_SRC_DIRECTIVE + "script-src", // SCRIPT_SRC_DIRECTIVE + "object-src", // OBJECT_SRC_DIRECTIVE + "style-src", // STYLE_SRC_DIRECTIVE + "img-src", // IMG_SRC_DIRECTIVE + "media-src", // MEDIA_SRC_DIRECTIVE + "frame-src", // FRAME_SRC_DIRECTIVE + "font-src", // FONT_SRC_DIRECTIVE + "connect-src", // CONNECT_SRC_DIRECTIVE + "report-uri", // REPORT_URI_DIRECTIVE + "frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE + "reflected-xss", // REFLECTED_XSS_DIRECTIVE + "base-uri", // BASE_URI_DIRECTIVE + "form-action", // FORM_ACTION_DIRECTIVE + "manifest-src", // MANIFEST_SRC_DIRECTIVE + "upgrade-insecure-requests", // UPGRADE_IF_INSECURE_DIRECTIVE + "child-src", // CHILD_SRC_DIRECTIVE + "block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT + "sandbox", // SANDBOX_DIRECTIVE + "worker-src", // WORKER_SRC_DIRECTIVE + "navigate-to", // NAVIGATE_TO_DIRECTIVE + "script-src-elem", // SCRIPT_SRC_ELEM_DIRECTIVE + "script-src-attr", // SCRIPT_SRC_ATTR_DIRECTIVE + "style-src-elem", // STYLE_SRC_ELEM_DIRECTIVE + "style-src-attr", // STYLE_SRC_ATTR_DIRECTIVE +}; + +inline const char* CSP_CSPDirectiveToString(CSPDirective aDir) { + return CSPStrDirectives[static_cast<uint32_t>(aDir)]; +} + +inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir) { + nsString lowerDir = PromiseFlatString(aDir); + ToLowerCase(lowerDir); + + uint32_t numDirs = (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0])); + for (uint32_t i = 1; i < numDirs; i++) { + if (lowerDir.EqualsASCII(CSPStrDirectives[i])) { + return static_cast<CSPDirective>(i); + } + } + return nsIContentSecurityPolicy::NO_DIRECTIVE; +} + +#define FOR_EACH_CSP_KEYWORD(MACRO) \ + MACRO(CSP_SELF, "'self'") \ + MACRO(CSP_UNSAFE_INLINE, "'unsafe-inline'") \ + MACRO(CSP_UNSAFE_EVAL, "'unsafe-eval'") \ + MACRO(CSP_UNSAFE_HASHES, "'unsafe-hashes'") \ + MACRO(CSP_NONE, "'none'") \ + MACRO(CSP_NONCE, "'nonce-") \ + MACRO(CSP_REPORT_SAMPLE, "'report-sample'") \ + MACRO(CSP_STRICT_DYNAMIC, "'strict-dynamic'") \ + MACRO(CSP_UNSAFE_ALLOW_REDIRECTS, "'unsafe-allow-redirects'") \ + MACRO(CSP_WASM_UNSAFE_EVAL, "'wasm-unsafe-eval'") + +enum CSPKeyword { +#define KEYWORD_ENUM(id_, string_) id_, + FOR_EACH_CSP_KEYWORD(KEYWORD_ENUM) +#undef KEYWORD_ENUM + + // CSP_LAST_KEYWORD_VALUE always needs to be the last element in the enum + // because we use it to calculate the size for the char* array. + CSP_LAST_KEYWORD_VALUE, + + // Putting CSP_HASH after the delimitor, because CSP_HASH is not a valid + // keyword (hash uses e.g. sha256, sha512) but we use CSP_HASH internally + // to identify allowed hashes in ::allows. + CSP_HASH +}; + +// The keywords, in UTF-8 form. +static const char* gCSPUTF8Keywords[] = { +#define KEYWORD_UTF8_LITERAL(id_, string_) string_, + FOR_EACH_CSP_KEYWORD(KEYWORD_UTF8_LITERAL) +#undef KEYWORD_UTF8_LITERAL +}; + +// The keywords, in UTF-16 form. +static const char16_t* gCSPUTF16Keywords[] = { +#define KEYWORD_UTF16_LITERAL(id_, string_) u"" string_, + FOR_EACH_CSP_KEYWORD(KEYWORD_UTF16_LITERAL) +#undef KEYWORD_UTF16_LITERAL +}; + +#undef FOR_EACH_CSP_KEYWORD + +inline const char* CSP_EnumToUTF8Keyword(enum CSPKeyword aKey) { + // Make sure all elements in enum CSPKeyword got added to gCSPUTF8Keywords. + static_assert((sizeof(gCSPUTF8Keywords) / sizeof(gCSPUTF8Keywords[0]) == + CSP_LAST_KEYWORD_VALUE), + "CSP_LAST_KEYWORD_VALUE != length(gCSPUTF8Keywords)"); + + if (static_cast<uint32_t>(aKey) < + static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) { + return gCSPUTF8Keywords[static_cast<uint32_t>(aKey)]; + } + return "error: invalid keyword in CSP_EnumToUTF8Keyword"; +} + +inline const char16_t* CSP_EnumToUTF16Keyword(enum CSPKeyword aKey) { + // Make sure all elements in enum CSPKeyword got added to gCSPUTF16Keywords. + static_assert((sizeof(gCSPUTF16Keywords) / sizeof(gCSPUTF16Keywords[0]) == + CSP_LAST_KEYWORD_VALUE), + "CSP_LAST_KEYWORD_VALUE != length(gCSPUTF16Keywords)"); + + if (static_cast<uint32_t>(aKey) < + static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) { + return gCSPUTF16Keywords[static_cast<uint32_t>(aKey)]; + } + return u"error: invalid keyword in CSP_EnumToUTF16Keyword"; +} + +inline CSPKeyword CSP_UTF16KeywordToEnum(const nsAString& aKey) { + nsString lowerKey = PromiseFlatString(aKey); + ToLowerCase(lowerKey); + + for (uint32_t i = 0; i < CSP_LAST_KEYWORD_VALUE; i++) { + if (lowerKey.Equals(gCSPUTF16Keywords[i])) { + return static_cast<CSPKeyword>(i); + } + } + NS_ASSERTION(false, "Can not convert unknown Keyword to Enum"); + return CSP_LAST_KEYWORD_VALUE; +} + +nsresult CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp, + const nsAString& aHeaderValue, + bool aReportOnly); + +/* =============== Helpers ================== */ + +class nsCSPHostSrc; + +nsCSPHostSrc* CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI); +bool CSP_IsEmptyDirective(const nsAString& aValue, const nsAString& aDir); +bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir); +bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey); +bool CSP_IsQuotelessKeyword(const nsAString& aKey); +CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType); + +class nsCSPSrcVisitor; + +void CSP_PercentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr); +bool CSP_ShouldResponseInheritCSP(nsIChannel* aChannel); + +void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, + const nsAString& aPolicyStr); + +/* =============== nsCSPSrc ================== */ + +class nsCSPBaseSrc { + public: + nsCSPBaseSrc(); + virtual ~nsCSPBaseSrc(); + + virtual bool permits(nsIURI* aUri, const nsAString& aNonce, + bool aWasRedirected, bool aReportOnly, + bool aUpgradeInsecure, bool aParserCreated) const; + virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const; + virtual bool visit(nsCSPSrcVisitor* aVisitor) const = 0; + virtual void toString(nsAString& outStr) const = 0; + + virtual void invalidate() const { mInvalidated = true; } + + virtual bool isReportSample() const { return false; } + + protected: + // invalidate srcs if 'script-dynamic' is present or also invalidate + // unsafe-inline' if nonce- or hash-source specified + mutable bool mInvalidated; +}; + +/* =============== nsCSPSchemeSrc ============ */ + +class nsCSPSchemeSrc : public nsCSPBaseSrc { + public: + explicit nsCSPSchemeSrc(const nsAString& aScheme); + virtual ~nsCSPSchemeSrc(); + + bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, + bool aReportOnly, bool aUpgradeInsecure, + bool aParserCreated) const override; + bool visit(nsCSPSrcVisitor* aVisitor) const override; + void toString(nsAString& outStr) const override; + + inline void getScheme(nsAString& outStr) const { outStr.Assign(mScheme); }; + + private: + nsString mScheme; +}; + +/* =============== nsCSPHostSrc ============== */ + +class nsCSPHostSrc : public nsCSPBaseSrc { + public: + explicit nsCSPHostSrc(const nsAString& aHost); + virtual ~nsCSPHostSrc(); + + bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, + bool aReportOnly, bool aUpgradeInsecure, + bool aParserCreated) const override; + bool visit(nsCSPSrcVisitor* aVisitor) const override; + void toString(nsAString& outStr) const override; + + void setScheme(const nsAString& aScheme); + void setPort(const nsAString& aPort); + void appendPath(const nsAString& aPath); + + inline void setGeneratedFromSelfKeyword() const { + mGeneratedFromSelfKeyword = true; + } + + inline void setIsUniqueOrigin() const { mIsUniqueOrigin = true; } + + inline void setWithinFrameAncestorsDir(bool aValue) const { + mWithinFrameAncstorsDir = aValue; + } + + inline void getScheme(nsAString& outStr) const { outStr.Assign(mScheme); }; + + inline void getHost(nsAString& outStr) const { outStr.Assign(mHost); }; + + inline void getPort(nsAString& outStr) const { outStr.Assign(mPort); }; + + inline void getPath(nsAString& outStr) const { outStr.Assign(mPath); }; + + private: + nsString mScheme; + nsString mHost; + nsString mPort; + nsString mPath; + mutable bool mGeneratedFromSelfKeyword; + mutable bool mIsUniqueOrigin; + mutable bool mWithinFrameAncstorsDir; +}; + +/* =============== nsCSPKeywordSrc ============ */ + +class nsCSPKeywordSrc : public nsCSPBaseSrc { + public: + explicit nsCSPKeywordSrc(CSPKeyword aKeyword); + virtual ~nsCSPKeywordSrc(); + + bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const override; + bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, + bool aReportOnly, bool aUpgradeInsecure, + bool aParserCreated) const override; + bool visit(nsCSPSrcVisitor* aVisitor) const override; + void toString(nsAString& outStr) const override; + + inline CSPKeyword getKeyword() const { return mKeyword; }; + + inline void invalidate() const override { + // keywords that need to invalidated + if (mKeyword == CSP_SELF || mKeyword == CSP_UNSAFE_INLINE || + mKeyword == CSP_REPORT_SAMPLE) { + mInvalidated = true; + } + } + + bool isReportSample() const override { return mKeyword == CSP_REPORT_SAMPLE; } + + private: + CSPKeyword mKeyword; +}; + +/* =============== nsCSPNonceSource =========== */ + +class nsCSPNonceSrc : public nsCSPBaseSrc { + public: + explicit nsCSPNonceSrc(const nsAString& aNonce); + virtual ~nsCSPNonceSrc(); + + bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, + bool aReportOnly, bool aUpgradeInsecure, + bool aParserCreated) const override; + bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const override; + bool visit(nsCSPSrcVisitor* aVisitor) const override; + void toString(nsAString& outStr) const override; + + inline void getNonce(nsAString& outStr) const { outStr.Assign(mNonce); }; + + inline void invalidate() const override { + // overwrite nsCSPBaseSRC::invalidate() and explicitily + // do *not* invalidate, because 'strict-dynamic' should + // not invalidate nonces. + } + + private: + nsString mNonce; +}; + +/* =============== nsCSPHashSource ============ */ + +class nsCSPHashSrc : public nsCSPBaseSrc { + public: + nsCSPHashSrc(const nsAString& algo, const nsAString& hash); + virtual ~nsCSPHashSrc(); + + bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const override; + void toString(nsAString& outStr) const override; + bool visit(nsCSPSrcVisitor* aVisitor) const override; + + inline void getAlgorithm(nsAString& outStr) const { + outStr.Assign(mAlgorithm); + }; + + inline void getHash(nsAString& outStr) const { outStr.Assign(mHash); }; + + inline void invalidate() const override { + // overwrite nsCSPBaseSRC::invalidate() and explicitily + // do *not* invalidate, because 'strict-dynamic' should + // not invalidate hashes. + } + + private: + nsString mAlgorithm; + nsString mHash; +}; + +/* =============== nsCSPReportURI ============ */ + +class nsCSPReportURI : public nsCSPBaseSrc { + public: + explicit nsCSPReportURI(nsIURI* aURI); + virtual ~nsCSPReportURI(); + + bool visit(nsCSPSrcVisitor* aVisitor) const override; + void toString(nsAString& outStr) const override; + + private: + nsCOMPtr<nsIURI> mReportURI; +}; + +/* =============== nsCSPSandboxFlags ================== */ + +class nsCSPSandboxFlags : public nsCSPBaseSrc { + public: + explicit nsCSPSandboxFlags(const nsAString& aFlags); + virtual ~nsCSPSandboxFlags(); + + bool visit(nsCSPSrcVisitor* aVisitor) const override; + void toString(nsAString& outStr) const override; + + private: + nsString mFlags; +}; + +/* =============== nsCSPSrcVisitor ================== */ + +class nsCSPSrcVisitor { + public: + virtual bool visitSchemeSrc(const nsCSPSchemeSrc& src) = 0; + + virtual bool visitHostSrc(const nsCSPHostSrc& src) = 0; + + virtual bool visitKeywordSrc(const nsCSPKeywordSrc& src) = 0; + + virtual bool visitNonceSrc(const nsCSPNonceSrc& src) = 0; + + virtual bool visitHashSrc(const nsCSPHashSrc& src) = 0; + + protected: + explicit nsCSPSrcVisitor() = default; + virtual ~nsCSPSrcVisitor() = default; +}; + +/* =============== nsCSPDirective ============= */ + +class nsCSPDirective { + public: + explicit nsCSPDirective(CSPDirective aDirective); + virtual ~nsCSPDirective(); + + virtual bool permits(nsIURI* aUri, const nsAString& aNonce, + bool aWasRedirected, bool aReportOnly, + bool aUpgradeInsecure, bool aParserCreated) const; + virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const; + virtual void toString(nsAString& outStr) const; + void toDomCSPStruct(mozilla::dom::CSP& outCSP) const; + + virtual void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) { + mSrcs = aSrcs.Clone(); + } + + inline bool isDefaultDirective() const { + return mDirective == nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE; + } + + virtual bool equals(CSPDirective aDirective) const; + + void getReportURIs(nsTArray<nsString>& outReportURIs) const; + + bool visitSrcs(nsCSPSrcVisitor* aVisitor) const; + + virtual void getDirName(nsAString& outStr) const; + + bool hasReportSampleKeyword() const; + + protected: + CSPDirective mDirective; + nsTArray<nsCSPBaseSrc*> mSrcs; +}; + +/* =============== nsCSPChildSrcDirective ============= */ + +/* + * In CSP 3 child-src is deprecated. For backwards compatibility + * child-src needs to restrict: + * (*) frames, in case frame-src is not expicitly specified + * (*) workers, in case worker-src is not expicitly specified + */ +class nsCSPChildSrcDirective : public nsCSPDirective { + public: + explicit nsCSPChildSrcDirective(CSPDirective aDirective); + virtual ~nsCSPChildSrcDirective(); + + void setRestrictFrames() { mRestrictFrames = true; } + + void setRestrictWorkers() { mRestrictWorkers = true; } + + virtual bool equals(CSPDirective aDirective) const override; + + private: + bool mRestrictFrames; + bool mRestrictWorkers; +}; + +/* =============== nsCSPScriptSrcDirective ============= */ + +/* + * In CSP 3 worker-src restricts workers, for backwards compatibily + * script-src has to restrict workers as the ultimate fallback if + * neither worker-src nor child-src is present in a CSP. + */ +class nsCSPScriptSrcDirective : public nsCSPDirective { + public: + explicit nsCSPScriptSrcDirective(CSPDirective aDirective); + virtual ~nsCSPScriptSrcDirective(); + + void setRestrictWorkers() { mRestrictWorkers = true; } + void setRestrictScriptElem() { mRestrictScriptElem = true; } + void setRestrictScriptAttr() { mRestrictScriptAttr = true; } + + bool equals(CSPDirective aDirective) const override; + + private: + bool mRestrictWorkers = false; + bool mRestrictScriptElem = false; + bool mRestrictScriptAttr = false; +}; + +/* =============== nsCSPStyleSrcDirective ============= */ + +/* + * In CSP 3 style-src is use as a fallback for style-src-elem and + * style-src-attr. + */ +class nsCSPStyleSrcDirective : public nsCSPDirective { + public: + explicit nsCSPStyleSrcDirective(CSPDirective aDirective); + virtual ~nsCSPStyleSrcDirective(); + + void setRestrictStyleElem() { mRestrictStyleElem = true; } + void setRestrictStyleAttr() { mRestrictStyleAttr = true; } + + bool equals(CSPDirective aDirective) const override; + + private: + bool mRestrictStyleElem = false; + bool mRestrictStyleAttr = false; +}; + +/* =============== nsBlockAllMixedContentDirective === */ + +class nsBlockAllMixedContentDirective : public nsCSPDirective { + public: + explicit nsBlockAllMixedContentDirective(CSPDirective aDirective); + ~nsBlockAllMixedContentDirective(); + + bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, + bool aReportOnly, bool aUpgradeInsecure, + bool aParserCreated) const override { + return false; + } + + bool permits(nsIURI* aUri) const { return false; } + + bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const override { + return false; + } + + void toString(nsAString& outStr) const override; + + void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) override { + MOZ_ASSERT(false, "block-all-mixed-content does not hold any srcs"); + } + + void getDirName(nsAString& outStr) const override; +}; + +/* =============== nsUpgradeInsecureDirective === */ + +/* + * Upgrading insecure requests includes the following actors: + * (1) CSP: + * The CSP implementation allowlists the http-request + * in case the policy is executed in enforcement mode. + * The CSP implementation however does not allow http + * requests to succeed if executed in report-only mode. + * In such a case the CSP implementation reports the + * error back to the page. + * + * (2) MixedContent: + * The evalution of MixedContent allowlists all http + * requests with the promise that the http requests + * gets upgraded to https before any data is fetched + * from the network. + * + * (3) CORS: + * Does not consider the http request to be of a + * different origin in case the scheme is the only + * difference in otherwise matching URIs. + * + * (4) nsHttpChannel: + * Before connecting, the channel gets redirected + * to use https. + * + * (5) WebSocketChannel: + * Similar to the httpChannel, the websocketchannel + * gets upgraded from ws to wss. + */ +class nsUpgradeInsecureDirective : public nsCSPDirective { + public: + explicit nsUpgradeInsecureDirective(CSPDirective aDirective); + ~nsUpgradeInsecureDirective(); + + bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, + bool aReportOnly, bool aUpgradeInsecure, + bool aParserCreated) const override { + return false; + } + + bool permits(nsIURI* aUri) const { return false; } + + bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, + bool aParserCreated) const override { + return false; + } + + void toString(nsAString& outStr) const override; + + void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) override { + MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); + } + + void getDirName(nsAString& outStr) const override; +}; + +/* =============== nsCSPPolicy ================== */ + +class nsCSPPolicy { + public: + nsCSPPolicy(); + virtual ~nsCSPPolicy(); + + bool permits(CSPDirective aDirective, nsIURI* aUri, const nsAString& aNonce, + bool aWasRedirected, bool aSpecific, bool aParserCreated, + nsAString& outViolatedDirective) const; + bool allows(CSPDirective aDirective, enum CSPKeyword aKeyword, + const nsAString& aHashOrNonce, bool aParserCreated) const; + void toString(nsAString& outStr) const; + void toDomCSPStruct(mozilla::dom::CSP& outCSP) const; + + inline void addDirective(nsCSPDirective* aDir) { + mDirectives.AppendElement(aDir); + } + + inline void addUpgradeInsecDir(nsUpgradeInsecureDirective* aDir) { + mUpgradeInsecDir = aDir; + addDirective(aDir); + } + + bool hasDirective(CSPDirective aDir) const; + + inline void setDeliveredViaMetaTagFlag(bool aFlag) { + mDeliveredViaMetaTag = aFlag; + } + + inline bool getDeliveredViaMetaTagFlag() const { + return mDeliveredViaMetaTag; + } + + inline void setReportOnlyFlag(bool aFlag) { mReportOnly = aFlag; } + + inline bool getReportOnlyFlag() const { return mReportOnly; } + + void getReportURIs(nsTArray<nsString>& outReportURIs) const; + + void getDirectiveStringAndReportSampleForContentType( + CSPDirective aDirective, nsAString& outDirective, + bool* aReportSample) const; + + void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const; + + uint32_t getSandboxFlags() const; + + inline uint32_t getNumDirectives() const { return mDirectives.Length(); } + + bool visitDirectiveSrcs(CSPDirective aDir, nsCSPSrcVisitor* aVisitor) const; + + bool allowsNavigateTo(nsIURI* aURI, bool aWasRedirected, + bool aEnforceAllowlist) const; + + private: + nsUpgradeInsecureDirective* mUpgradeInsecDir; + nsTArray<nsCSPDirective*> mDirectives; + bool mReportOnly; + bool mDeliveredViaMetaTag; +}; + +#endif /* nsCSPUtils_h___ */ |