tor-browser

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

CookieJarSettings.h (12267B)


      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 mozilla_net_CookieJarSettings_h
      8 #define mozilla_net_CookieJarSettings_h
      9 
     10 #include "mozilla/Maybe.h"
     11 #include "mozilla/net/NeckoChannelParams.h"
     12 
     13 #include "nsICookieJarSettings.h"
     14 #include "nsIPermission.h"
     15 #include "nsTArray.h"
     16 
     17 #define COOKIEJARSETTINGS_CONTRACTID "@mozilla.org/cookieJarSettings;1"
     18 // 4ce234f1-52e8-47a9-8c8d-b02f815733c7
     19 #define COOKIEJARSETTINGS_CID \
     20  {0x4ce234f1, 0x52e8, 0x47a9, {0x8c, 0x8d, 0xb0, 0x2f, 0x81, 0x57, 0x33, 0xc7}}
     21 
     22 namespace mozilla {
     23 namespace net {
     24 
     25 class CookieJarSettingsArgs;
     26 
     27 using CookiePermissionsArgsData = nsTArray<net::CookiePermissionData>;
     28 
     29 /**
     30 * CookieJarSettings
     31 * ~~~~~~~~~~~~~~
     32 *
     33 * CookieJarSettings is a snapshot of the cookie jar's configurations in a
     34 * precise moment of time, such as the cookie policy and cookie permissions.
     35 * This object is used by top-level documents to have a consistent cookie jar
     36 * configuration also in case the user changes it. New configurations will apply
     37 * only to new top-level documents.
     38 *
     39 * CookieJarSettings creation
     40 * ~~~~~~~~~~~~~~~~~~~~~~~
     41 *
     42 * CookieJarSettings is created when the top-level document's nsIChannel's
     43 * nsILoadInfo is constructed. Any sub-resource and any sub-document inherits it
     44 * from that nsILoadInfo. Also dedicated workers and their resources inherit it
     45 * from the parent document.
     46 *
     47 * SharedWorkers and ServiceWorkers have their own CookieJarSettings because
     48 * they don't have a single parent document (SharedWorkers could have more than
     49 * one, ServiceWorkers have none).
     50 *
     51 * In Chrome code, we have a new CookieJarSettings when we download resources
     52 * via 'Save-as...' and we also have a new CookieJarSettings for favicon
     53 * downloading.
     54 *
     55 * Content-scripts WebExtensions also have their own CookieJarSettings because
     56 * they don't have a direct access to the document they are running into.
     57 *
     58 * Anything else will have a special CookieJarSettings which blocks everything
     59 * (CookieJarSettings::GetBlockingAll()) by forcing BEHAVIOR_REJECT as policy.
     60 * When this happens, that context will not have access to the cookie jar and no
     61 * cookies are sent or received.
     62 *
     63 * Propagation of CookieJarSettings
     64 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     65 *
     66 * CookieJarSettings are shared inside the same top-level document via its
     67 * nsIChannel's nsILoadInfo.  This is done automatically if you pass a nsINode
     68 * to NS_NewChannel(), and it must be done manually if you use a different
     69 * channel constructor. For instance, this happens for any worker networking
     70 * operation.
     71 *
     72 * We use the same CookieJarSettings for any resource belonging to the top-level
     73 * document even if cross-origin. This makes the browser behave consistently a
     74 * scenario where A loads B which loads A again, and cookie policy/permission
     75 * changes in the meantime.
     76 *
     77 * Cookie Permissions propagation
     78 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     79 *
     80 * CookieJarSettings populates the known cookie permissions only when required.
     81 * Initially the list is empty, but when CookieJarSettings::CookiePermission()
     82 * is called, the requested permission is stored in the internal list if it
     83 * doesn't exist yet.
     84 *
     85 * This is actually nice because it relies on the permission propagation from
     86 * parent to content process. No extra IPC is required.
     87 *
     88 * Note that we store permissions with UNKNOWN_ACTION values too because they
     89 * can be set after the loading of the top-level document and we don't want to
     90 * return a different value when this happens.
     91 *
     92 * Use of CookieJarSettings
     93 * ~~~~~~~~~~~~~~~~~~~~~
     94 *
     95 * In theory, there should not be direct access to cookie permissions or
     96 * cookieBehavior pref. Everything should pass through CookieJarSettings.
     97 *
     98 * A reference to CookieJarSettings can be obtained from
     99 * nsILoadInfo::GetCookieJarSettings(), from Document::CookieJarSettings() and
    100 * from the WorkerPrivate::CookieJarSettings().
    101 *
    102 * CookieJarSettings is thread-safe, but the permission list must be touched
    103 * only on the main-thread.
    104 *
    105 * Testing
    106 * ~~~~~~~
    107 *
    108 * If you need to test the changing of cookie policy or a cookie permission, you
    109 * need to workaround CookieJarSettings. This can be done opening a new window
    110 * and running the test into that new global.
    111 */
    112 
    113 /**
    114 * Class that provides an nsICookieJarSettings implementation.
    115 */
    116 class CookieJarSettings final : public nsICookieJarSettings {
    117 public:
    118  typedef nsTArray<RefPtr<nsIPermission>> CookiePermissionList;
    119 
    120  NS_DECL_THREADSAFE_ISUPPORTS
    121  NS_DECL_NSICOOKIEJARSETTINGS
    122  NS_DECL_NSISERIALIZABLE
    123 
    124  static already_AddRefed<nsICookieJarSettings> GetBlockingAll(
    125      bool aShouldResistFingerprinting);
    126 
    127  enum CreateMode { eRegular, ePrivate };
    128 
    129  static already_AddRefed<nsICookieJarSettings> Create(
    130      CreateMode aMode, bool aShouldResistFingerprinting);
    131 
    132  static already_AddRefed<nsICookieJarSettings> Create(
    133      nsIPrincipal* aPrincipal);
    134 
    135  // This function should be only called for XPCOM. You should never use this
    136  // for other purposes.
    137  static already_AddRefed<nsICookieJarSettings> CreateForXPCOM();
    138 
    139  static already_AddRefed<nsICookieJarSettings> Create(
    140      uint32_t aCookieBehavior, const nsAString& aPartitionKey,
    141      bool aIsFirstPartyIsolated, bool aIsOnContentBlockingAllowList,
    142      bool aShouldResistFingerprinting);
    143 
    144  static CookieJarSettings* Cast(nsICookieJarSettings* aCS) {
    145    return static_cast<CookieJarSettings*>(aCS);
    146  }
    147 
    148  already_AddRefed<CookieJarSettings> Clone() {
    149    RefPtr<CookieJarSettings> clone = new CookieJarSettings(*this);
    150    return clone.forget();
    151  }
    152 
    153  void Serialize(CookieJarSettingsArgs& aData);
    154 
    155  static void Deserialize(const CookieJarSettingsArgs& aData,
    156                          nsICookieJarSettings** aCookieJarSettings);
    157 
    158  static CookiePermissionList DeserializeCookiePermissions(
    159      const CookiePermissionsArgsData& aPermissionData);
    160 
    161  // Merge the current CookieJarSettings with the new CookieJarSettingsArgs. It
    162  // returns a new merged CookieJarSettings.
    163  already_AddRefed<nsICookieJarSettings> Merge(
    164      const CookieJarSettingsArgs& aData);
    165 
    166  // We don't want to send this object from parent to child process if there are
    167  // no reasons. HasBeenChanged() returns true if the object has changed its
    168  // internal state and it must be sent beck to the content process.
    169  bool HasBeenChanged() const { return mToBeMerged; }
    170 
    171  void UpdateIsOnContentBlockingAllowList(nsIChannel* aChannel);
    172  void SetIsOnContentBlockingAllowList(bool aIsOnContentBlockingAllowList) {
    173    mIsOnContentBlockingAllowList = aIsOnContentBlockingAllowList;
    174  }
    175 
    176  void SetPartitionKey(nsIURI* aURI);
    177  void SetPartitionKey(const nsAString& aPartitionKey) {
    178    mPartitionKey = aPartitionKey;
    179  }
    180  const nsAString& GetPartitionKey() { return mPartitionKey; };
    181 
    182  void UpdatePartitionKeyForDocumentLoadedByChannel(nsIChannel* aChannel);
    183 
    184  void SetFingerprintingRandomizationKey(const nsTArray<uint8_t>& aKey) {
    185    mFingerprintingRandomKey.reset();
    186 
    187    mFingerprintingRandomKey.emplace(aKey.Clone());
    188  }
    189 
    190  // Utility function to test if the passed cookiebahvior is
    191  // BEHAVIOR_REJECT_TRACKER, BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN or
    192  // BEHAVIOR_REJECT_FOREIGN when
    193  // network.cookie.rejectForeignWithExceptions.enabled pref is set to true.
    194  static bool IsRejectThirdPartyContexts(uint32_t aCookieBehavior);
    195 
    196  void SetTopLevelWindowContextId(uint64_t aId) {
    197    mTopLevelWindowContextId = aId;
    198  }
    199  uint64_t GetTopLevelWindowContextId() { return mTopLevelWindowContextId; }
    200 
    201 private:
    202  enum State {
    203    // No cookie permissions are allowed to be stored in this object.
    204    eFixed,
    205 
    206    // Cookie permissions can be stored in case they are unknown when they are
    207    // asked or when they are sent from the parent process.
    208    eProgressive,
    209  };
    210 
    211  CookieJarSettings(uint32_t aCookieBehavior, bool aIsFirstPartyIsolated,
    212                    bool aShouldResistFingerprinting, State aState);
    213 
    214  CookieJarSettings(const CookieJarSettings& aOther) {
    215    mCookieBehavior = aOther.mCookieBehavior;
    216    mIsFirstPartyIsolated = aOther.mIsFirstPartyIsolated;
    217    mCookiePermissions = aOther.mCookiePermissions.Clone();
    218 
    219    mIsOnContentBlockingAllowList = aOther.mIsOnContentBlockingAllowList;
    220    mIsOnContentBlockingAllowListUpdated =
    221        aOther.mIsOnContentBlockingAllowListUpdated;
    222 
    223    mPartitionKey = aOther.mPartitionKey;
    224    mState = aOther.mState;
    225    mToBeMerged = aOther.mToBeMerged;
    226 
    227    mShouldResistFingerprinting = aOther.mShouldResistFingerprinting;
    228    if (aOther.mFingerprintingRandomKey.isSome()) {
    229      mFingerprintingRandomKey =
    230          Some(aOther.mFingerprintingRandomKey.ref().Clone());
    231    }
    232 
    233    mTopLevelWindowContextId = aOther.mTopLevelWindowContextId;
    234  }
    235 
    236  CookiePermissionList& GetCookiePermissionsListRef();
    237 
    238  ~CookieJarSettings();
    239 
    240  uint32_t mCookieBehavior;
    241  bool mIsFirstPartyIsolated;
    242  CookiePermissionList mCookiePermissions;
    243  CookiePermissionsArgsData mIPCCookiePermissions;
    244 
    245  bool mIsOnContentBlockingAllowList;
    246  bool mIsOnContentBlockingAllowListUpdated;
    247  nsString mPartitionKey;
    248  State mState;
    249 
    250  bool mToBeMerged;
    251 
    252  // DO NOT USE THIS MEMBER TO CHECK IF YOU SHOULD RESIST FINGERPRINTING.
    253  // USE THE nsContentUtils::ShouldResistFingerprinting() METHODS ONLY.
    254  //
    255  // As we move to fine-grained RFP control, we want to support per-domain
    256  // exemptions from ResistFingerprinting. Specifically the behavior should be
    257  // as such:
    258  //
    259  // Top-Level Document is on an Exempted Domain
    260  //    - RFP is disabled.
    261  //
    262  // Top-Level Document on an Exempted Domain embedding a non-exempted
    263  // cross-origin iframe
    264  //    - RFP in the iframe is enabled (NOT exempted). (**)
    265  //
    266  // Top-Level Document on an Exempted Domain embedding an exempted cross-origin
    267  // iframe
    268  //    - RFP in the iframe is disabled (exempted).
    269  //
    270  // Top-Level Document on a Non-Exempted Domain
    271  //    - RFP is enabled (NOT exempted).
    272  //
    273  // Top-Level Document on a Non-Exempted Domain embeds an exempted cross-origin
    274  // iframe
    275  //    - RFP in the iframe is enabled (NOT exempted). (*)
    276  //
    277  // Exempted Document (top-level or iframe) contacts any cross-origin domain
    278  //   (exempted or non-exempted)
    279  //    - RFP is disabled (exempted) for the request
    280  //
    281  // Non-Exempted Document (top-level or iframe) contacts any cross-origin
    282  // domain
    283  //   (exempted or non-exempted)
    284  //    - RFP is enabled (NOT exempted) for the request
    285  //
    286  // This boolean on CookieJarSettings will enable us to apply the most
    287  //   difficult rule, marked in (*). (It is difficult because the
    288  //   subdocument's loadinfo will look like it should be exempted.)
    289  // However if we trusted this member blindly, it would not correctly apply
    290  //   the one marked with (**). (Because it would inherit an exemption into
    291  //   a subdocument that should not be exempted.)
    292  // To handle this case, we only trust a CookieJar's ShouldRFP value if it
    293  //   says we should resist fingerprinting. If it says that we  _should not_,
    294  //   we continue and check the channel's URI or LoadInfo and if
    295  //   the domain specified there is not an exempted domain, enforce RFP anyway.
    296  //   This all occurrs in the nscontentUtils::ShouldResistFingerprinting
    297  //   functions which you should be using.
    298  bool mShouldResistFingerprinting;
    299 
    300  // The key used to generate the random noise for randomizing the browser
    301  // fingerprint. The key is decided by the session key and the top-level site.
    302  // So, the browse fingerprint will look different to the same tracker
    303  // under different top-level sites. Also, the fingerprint will change as
    304  // browsing session changes. This can prevent trackers to identify individuals
    305  // by using browser fingerprints.
    306  Maybe<nsTArray<uint8_t>> mFingerprintingRandomKey;
    307 
    308  // This field caches the top level window context id when loading the top
    309  // level document.
    310  uint64_t mTopLevelWindowContextId;
    311 };
    312 
    313 }  // namespace net
    314 }  // namespace mozilla
    315 
    316 #endif  // mozilla_net_CookieJarSettings_h