tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsCSPContext.h (10849B)


      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 nsCSPContext_h___
      8 #define nsCSPContext_h___
      9 
     10 #include "mozilla/StaticPrefs_security.h"
     11 #include "mozilla/dom/CSPViolationData.h"
     12 #include "mozilla/dom/SecurityPolicyViolationEvent.h"
     13 #include "mozilla/dom/nsCSPUtils.h"
     14 #include "nsIChannel.h"
     15 #include "nsIChannelEventSink.h"
     16 #include "nsIContentSecurityPolicy.h"
     17 #include "nsIInterfaceRequestor.h"
     18 #include "nsIStreamListener.h"
     19 #include "nsIWeakReferenceUtils.h"
     20 #include "nsXPCOM.h"
     21 
     22 #define NS_CSPCONTEXT_CONTRACTID "@mozilla.org/cspcontext;1"
     23 // 09d9ed1a-e5d4-4004-bfe0-27ceb923d9ac
     24 #define NS_CSPCONTEXT_CID \
     25  {0x09d9ed1a, 0xe5d4, 0x4004, {0xbf, 0xe0, 0x27, 0xce, 0xb9, 0x23, 0xd9, 0xac}}
     26 
     27 class nsINetworkInterceptController;
     28 class nsIEventTarget;
     29 struct ConsoleMsgQueueElem;
     30 
     31 namespace mozilla {
     32 namespace dom {
     33 class Element;
     34 }
     35 namespace ipc {
     36 class ContentSecurityPolicy;
     37 }
     38 }  // namespace mozilla
     39 
     40 class nsCSPContext : public nsIContentSecurityPolicy {
     41 public:
     42  NS_DECL_ISUPPORTS
     43  NS_DECL_NSICONTENTSECURITYPOLICY
     44  NS_DECL_NSISERIALIZABLE
     45 
     46  NS_DEFINE_STATIC_CID_ACCESSOR(NS_CSPCONTEXT_CID)
     47 
     48 protected:
     49  virtual ~nsCSPContext();
     50 
     51 public:
     52  nsCSPContext();
     53 
     54  static bool Equals(nsIContentSecurityPolicy* aCSP,
     55                     nsIContentSecurityPolicy* aOtherCSP);
     56 
     57  // Init a CSP from a different CSP
     58  nsresult InitFromOther(nsCSPContext* otherContext);
     59 
     60  // Used to suppress errors and warnings produced by the parser.
     61  // Use this when doing an one-off parsing of the CSP.
     62  void SuppressParserLogMessages() { mSuppressParserLogMessages = true; }
     63 
     64  /**
     65   * SetRequestContextWithDocument() needs to be called before the
     66   * innerWindowID is initialized on the document. Use this function
     67   * to call back to flush queued up console messages and initialize
     68   * the innerWindowID. Node, If SetRequestContextWithPrincipal() was
     69   * called then we do not have a innerWindowID anyway and hence
     70   * we can not flush messages to the correct console.
     71   */
     72  void flushConsoleMessages();
     73 
     74  void logToConsole(const char* aName, const nsTArray<nsString>& aParams,
     75                    const nsACString& aSourceName, const nsAString& aSourceLine,
     76                    uint32_t aLineNumber, uint32_t aColumnNumber,
     77                    uint32_t aSeverityFlag);
     78 
     79  /**
     80   * Construct SecurityPolicyViolationEventInit structure.
     81   *
     82   * @param aOriginalUri
     83   *        The original URI if the blocked content is a redirect, else null
     84   * @param aViolatedDirective
     85   *        the directive that was violated (string).
     86   * @param aScriptSample
     87   *        a sample of the violating inline script
     88   * @param aViolationEventInit
     89   *        The output
     90   */
     91  nsresult GatherSecurityPolicyViolationEventData(
     92      nsIURI* aOriginalURI, const nsAString& aEffectiveDirective,
     93      const mozilla::dom::CSPViolationData& aCSPViolationData,
     94      bool aReportSample,
     95      mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
     96 
     97  nsresult SendReports(
     98      const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
     99      uint32_t aViolatedPolicyIndex);
    100 
    101  nsresult SendReportsToEndpoints(
    102      nsAutoString& reportGroup,
    103      const mozilla::dom::SecurityPolicyViolationEventInit&
    104          aViolationEventInit);
    105 
    106  nsresult SendReportsToURIs(
    107      const nsTArray<nsString>& reportURIs,
    108      const mozilla::dom::SecurityPolicyViolationEventInit&
    109          aViolationEventInit);
    110 
    111  void HandleInternalPageViolation(
    112      const mozilla::dom::CSPViolationData& aCSPViolationData,
    113      const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
    114      const nsAString& aViolatedDirectiveNameAndValue);
    115 
    116  nsresult FireViolationEvent(
    117      mozilla::dom::Element* aTriggeringElement,
    118      nsICSPEventListener* aCSPEventListener,
    119      const mozilla::dom::SecurityPolicyViolationEventInit&
    120          aViolationEventInit);
    121 
    122  /**
    123   * Asynchronously notifies any nsIObservers listening to the CSP violation
    124   * topic that a violation occurred.  Also triggers report sending and console
    125   * logging.  All asynchronous on the main thread.
    126   *
    127   * @param aCSPEventListener Should be null when the violation stems from a
    128   *                          Window. Is required when the violation stems from
    129   *                          a Worker to be potentially notified about the
    130   *                          violation event.
    131   * @param aOriginalUri
    132   *        The original URI if the blocked content is a redirect, else null
    133   * @param aViolatedDirectiveName
    134   *        the directive that was violated (string).
    135   * @param aObserverSubject
    136   *        optional, subject sent to the nsIObservers listening to the CSP
    137   *        violation topic.
    138   */
    139  nsresult AsyncReportViolation(
    140      nsICSPEventListener* aCSPEventListener,
    141      mozilla::dom::CSPViolationData&& aCSPViolationData, nsIURI* aOriginalURI,
    142      const nsAString& aViolatedDirectiveName,
    143      const nsAString& aViolatedDirectiveNameAndValue,
    144      const nsAString& aObserverSubject, bool aReportSample);
    145 
    146  // Hands off! Don't call this method unless you know what you
    147  // are doing. It's only supposed to be called from within
    148  // the principal destructor to avoid a tangling pointer.
    149  void clearLoadingPrincipal() { mLoadingPrincipal = nullptr; }
    150 
    151  nsWeakPtr GetLoadingContext() { return mLoadingContext; }
    152 
    153  static uint32_t ScriptSampleMaxLength() {
    154    return std::max(
    155        mozilla::StaticPrefs::security_csp_reporting_script_sample_max_length(),
    156        0);
    157  }
    158 
    159  void AddIPCPolicy(const mozilla::ipc::ContentSecurityPolicy& aPolicy);
    160  void SerializePolicies(
    161      nsTArray<mozilla::ipc::ContentSecurityPolicy>& aPolicies);
    162 
    163  static nsCSPContext* Cast(nsIContentSecurityPolicy* aCSP) {
    164    return static_cast<nsCSPContext*>(aCSP);
    165  }
    166 
    167  [[nodiscard]] nsresult PolicyContainerRead(
    168      nsIObjectInputStream* aInputStream);
    169 
    170 private:
    171  enum class ForceReportSample { Yes, No };
    172 
    173  /**
    174   * @param aCSPEventListener see `nsCSPContext::AsyncReportViolation`'s csp
    175   *                          event listener argument.
    176   */
    177  void LogViolationDetailsUnchecked(
    178      nsICSPEventListener* aCSPEventListener,
    179      mozilla::dom::CSPViolationData&& aCSPViolationData,
    180      const nsAString& aObserverSubject, ForceReportSample aForceReportSample);
    181 
    182  bool ShouldThrottleReport(
    183      const mozilla::dom::SecurityPolicyViolationEventInit&
    184          aViolationEventInit);
    185 
    186  bool permitsInternal(CSPDirective aDir,
    187                       mozilla::dom::Element* aTriggeringElement,
    188                       nsICSPEventListener* aCSPEventListener,
    189                       nsILoadInfo* aLoadInfo, nsIURI* aContentLocation,
    190                       nsIURI* aOriginalURIIfRedirect, bool aSpecific,
    191                       bool aSendViolationReports,
    192                       bool aSendContentLocationInViolationReports);
    193 
    194  // helper to report inline script/style violations
    195  void ReportInlineViolation(CSPDirective aDirective,
    196                             mozilla::dom::Element* aTriggeringElement,
    197                             nsICSPEventListener* aCSPEventListener,
    198                             const nsAString& aNonce, bool aReportSample,
    199                             const nsAString& aSourceCode,
    200                             const nsAString& aViolatedDirective,
    201                             const nsAString& aViolatedDirectiveString,
    202                             CSPDirective aEffectiveDirective,
    203                             uint32_t aViolatedPolicyIndex,
    204                             uint32_t aLineNumber, uint32_t aColumnNumber);
    205 
    206  enum class PolicyDataVersion {
    207    Pre136,   // Before v136
    208    Post136,  // v136-137 with bug 1901492 or v138+ with bug 1958259. (This is
    209              // the current version)
    210    V138_9PreRelease,  // v138 Beta/Nightly and v139 Nightly with bug 1942306
    211                       // and without bug 1958259
    212  };
    213 
    214  nsresult TryReadPolicies(PolicyDataVersion aVersion,
    215                           nsIObjectInputStream* aStream, uint32_t aNumPolicies,
    216                           bool aForPolicyContainer);
    217 
    218  [[nodiscard]] nsresult ReadImpl(nsIObjectInputStream* aStream,
    219                                  bool aForPolicyContainer);
    220 
    221  nsCString mReferrer;
    222  uint64_t mInnerWindowID;          // See `nsPIDOMWindowInner::mWindowID`.
    223  bool mSkipAllowInlineStyleCheck;  // used to allow Devtools to edit styles
    224  // When deserializing an nsCSPContext instance, we initially just keep the
    225  // policies unparsed. We will only reconstruct actual CSP policy instances
    226  // when there's an attempt to use the CSP. Given a better way to serialize/
    227  // deserialize individual nsCSPPolicy objects, this performance
    228  // optimization could go away.
    229  nsTArray<mozilla::ipc::ContentSecurityPolicy> mIPCPolicies;
    230  nsTArray<nsCSPPolicy*> mPolicies;
    231  nsCOMPtr<nsIURI> mSelfURI;
    232  nsCOMPtr<nsILoadGroup> mCallingChannelLoadGroup;
    233  nsWeakPtr mLoadingContext;
    234  nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
    235 
    236  bool mSuppressParserLogMessages = false;
    237 
    238  // helper members used to queue up web console messages till
    239  // the windowID becomes available. see flushConsoleMessages()
    240  nsTArray<ConsoleMsgQueueElem> mConsoleMsgQueue;
    241  bool mQueueUpMessages;
    242  nsCOMPtr<nsIEventTarget> mEventTarget;
    243 
    244  mozilla::TimeStamp mSendReportLimitSpanStart;
    245  uint32_t mSendReportLimitCount = 1;
    246  bool mWarnedAboutTooManyReports = false;
    247  RequireTrustedTypesForDirectiveState mRequireTrustedTypesForDirectiveState =
    248      RequireTrustedTypesForDirectiveState::NONE;
    249 };
    250 
    251 // Class that listens to violation report transmission and logs errors.
    252 class CSPViolationReportListener : public nsIStreamListener {
    253 public:
    254  NS_DECL_NSISTREAMLISTENER
    255  NS_DECL_NSIREQUESTOBSERVER
    256  NS_DECL_ISUPPORTS
    257 
    258 public:
    259  CSPViolationReportListener();
    260 
    261 protected:
    262  virtual ~CSPViolationReportListener();
    263 };
    264 
    265 // The POST of the violation report (if it happens) should not follow
    266 // redirects, per the spec. hence, we implement an nsIChannelEventSink
    267 // with an object so we can tell XHR to abort if a redirect happens.
    268 class CSPReportRedirectSink final : public nsIChannelEventSink,
    269                                    public nsIInterfaceRequestor {
    270 public:
    271  NS_DECL_NSICHANNELEVENTSINK
    272  NS_DECL_NSIINTERFACEREQUESTOR
    273  NS_DECL_ISUPPORTS
    274 
    275 public:
    276  CSPReportRedirectSink();
    277 
    278  void SetInterceptController(
    279      nsINetworkInterceptController* aInterceptController);
    280 
    281 protected:
    282  virtual ~CSPReportRedirectSink();
    283 
    284 private:
    285  nsCOMPtr<nsINetworkInterceptController> mInterceptController;
    286 };
    287 
    288 #endif /* nsCSPContext_h___ */