1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_COOKIES_SITE_FOR_COOKIES_H_ 6 #define NET_COOKIES_SITE_FOR_COOKIES_H_ 7 8 #include <string> 9 10 #include "base/gtest_prod_util.h" 11 #include "net/base/net_export.h" 12 #include "net/base/schemeful_site.h" 13 #include "url/gurl.h" 14 #include "url/origin.h" 15 16 namespace net { 17 18 // Represents which origins are to be considered same-site for a given 19 // context (e.g. frame). There may be none. 20 // 21 // The currently implemented policy ("schemeful") is that 22 // two valid URLs would be considered same-site if either: 23 // 1) They both have compatible schemes along with non-empty and equal 24 // registrable domains or hostnames/IPs. Two schemes are compatible if they 25 // are either equal, or are both in {http, ws}, or are both in {https, wss}. 26 // E.x. "https://example.com" and "wss://example.com" 27 // 2) They both have empty hostnames and exactly equal schemes. E.x. "file://" 28 // and "file://" 29 // 30 // With the SchemefulSameSite feature disabled the policy ("schemeless") is that 31 // two valid URLs would be considered the same site if either: 1) They both have 32 // non-empty and equal registrable domains or hostnames/IPs. E.x. "example.com" 33 // and "example.com" 2) They both have empty hostnames and equal schemes. E.x. 34 // "file://" and "file://" 35 // 36 // 37 // Invalid URLs are never same-site to anything. 38 class NET_EXPORT SiteForCookies { 39 public: 40 // Matches nothing. 41 SiteForCookies(); 42 43 SiteForCookies(const SiteForCookies& other); 44 SiteForCookies(SiteForCookies&& other); 45 46 explicit SiteForCookies(const SchemefulSite& schemeful_site); 47 48 ~SiteForCookies(); 49 50 SiteForCookies& operator=(const SiteForCookies& other); 51 SiteForCookies& operator=(SiteForCookies&& other); 52 53 // Tries to construct an instance from (potentially untrusted) values of 54 // site() and schemefully_same() that got received over an RPC. 55 // 56 // Returns whether successful or not. Doesn't touch `*out` if false is 57 // returned. This returning `true` does not mean that whoever sent the values 58 // did not lie, merely that they are well-formed. 59 static bool FromWire(const SchemefulSite& site, 60 bool schemefully_same, 61 SiteForCookies* out); 62 63 // If the origin is opaque, returns SiteForCookies that matches nothing. 64 // 65 // If it's not opaque, returns one that matches URLs which are considered to 66 // be same-party as URLs from `origin`. 67 static SiteForCookies FromOrigin(const url::Origin& origin); 68 69 // Equivalent to FromOrigin(url::Origin::Create(url)). 70 static SiteForCookies FromUrl(const GURL& url); 71 72 // Returns a string with the values of the member variables. 73 // `schemefully_same` being false does not change the output. 74 std::string ToDebugString() const; 75 76 // Returns true if `url` should be considered first-party to the context 77 // `this` represents. 78 bool IsFirstParty(const GURL& url) const; 79 80 // Don't use this function unless you know what you're doing, if you're unsure 81 // you probably want IsFirstParty(). 82 // 83 // If `compute_schemefully` is true this function will return true if `url` 84 // should be considered first-party to the context `this` represents when the 85 // compatibility of the schemes are taken into account. 86 // 87 // If `compute_schemefully` is false this function will return true if `url` 88 // should be considered first-party to the context `this` represents when the 89 // compatibility of the scheme are not taken into account. Note that schemes 90 // are still compared for exact equality if neither `this` nor `url` have a 91 // registered domain. 92 bool IsFirstPartyWithSchemefulMode(const GURL& url, 93 bool compute_schemefully) const; 94 95 // Returns true if `other.IsFirstParty()` is true for exactly the same URLs 96 // as `this->IsFirstParty` (potentially none). Two SFCs are also considered 97 // equivalent if neither ever returns true for `IsFirstParty()`. I.e., both 98 // are null. 99 bool IsEquivalent(const SiteForCookies& other) const; 100 101 // Compares a "candidate" SFC, `this`, with an origin (represented as a 102 // SchemefulSite) from the frame tree and revises `this` to be null as 103 // required. 104 // 105 // This method is used when a sub-frame needs to have its SiteForCookies 106 // computed, which is dependent on all of its ancestors' origins (`other`). If 107 // its or any of its ancestors' frame's origins are not first-party with the 108 // top-level origin then this frame's SFC should be null. Otherwise, if it and 109 // all its ancestors are first-party with the top-level frame, the frame's 110 // SFC is the same as the top-level. 111 // 112 // This computation gets a bit tricky when considering "Schemeful Same-Site" 113 // as we don't know ahead of time if `this` is going to be used for a 114 // schemeful or schemeless computation later down the line, so we need to 115 // be careful to not completely nullify the entire SFC just because an `other` 116 // isn't schemefully first-party. If the computation is schemelessly 117 // first-party but *not schemefully* first-party then only the 118 // `schemefully_same_` flag will be cleared (which informs other functions to 119 // treat `this` as null for schemeful purposes). If the computation is not 120 // schemelessly first-party then `this` will have an opaque `site_` which 121 // completely nullifies it. 122 // 123 // This function should be called on all ancestors up to the top-level frame 124 // unless it returns false in which case `this` has been completely nullified 125 // and the caller may stop early. 126 // 127 // (This function's return value is the same as IsEquivalent() when "Schemeful 128 // Same-Site" is disabled.) 129 bool CompareWithFrameTreeSiteAndRevise(const SchemefulSite& other); 130 131 // Converts an Origin into a SchemefulSite and then calls 132 //`CompareWithFrameTreeSiteAndRevise(SchemefulSite)` 133 // 134 // If possible, prefer `CompareWithFrameTreeSiteAndRevise(SchemefulSite)` 135 // for performance reasons. 136 bool CompareWithFrameTreeOriginAndRevise(const url::Origin& other); 137 138 // Returns a URL that's first party to this SiteForCookies (an empty URL if 139 // none) --- that is, it has the property that 140 // site_for_cookies.IsEquivalent( 141 // SiteForCookies::FromUrl(site_for_cookies.RepresentativeUrl())); 142 // 143 // The convention used here (empty for nothing) is equivalent to that 144 // used before SiteForCookies existed as a type; this method is mostly 145 // meant to help incrementally migrate towards the type. New code probably 146 // should not need this. 147 GURL RepresentativeUrl() const; 148 site()149 const SchemefulSite& site() const { return site_; } 150 151 // Guaranteed to be lowercase. scheme()152 const std::string& scheme() const { return site_.site_as_origin_.scheme(); } 153 registrable_domain()154 const std::string& registrable_domain() const { 155 return site_.site_as_origin_.host(); 156 } 157 158 // Used for serialization/deserialization. This value is irrelevant if 159 // site().opaque() is true. schemefully_same()160 bool schemefully_same() const { return schemefully_same_; } 161 SetSchemefullySameForTesting(bool schemefully_same)162 void SetSchemefullySameForTesting(bool schemefully_same) { 163 schemefully_same_ = schemefully_same; 164 } 165 166 // Returns true if this SiteForCookies matches nothing. 167 // If the SchemefulSameSite feature is enabled then !schemefully_same_ causes 168 // this function to return true. 169 bool IsNull() const; 170 171 // Allows SiteForCookies to be used as a key in STL (for example, a std::set 172 // or std::map). 173 NET_EXPORT friend bool operator<(const SiteForCookies& lhs, 174 const SiteForCookies& rhs); 175 176 private: 177 FRIEND_TEST_ALL_PREFIXES(SiteForCookiesTest, SameScheme); 178 FRIEND_TEST_ALL_PREFIXES(SiteForCookiesTest, SameSchemeOpaque); 179 180 bool IsSchemefullyFirstParty(const GURL& url) const; 181 182 bool IsSchemelesslyFirstParty(const GURL& url) const; 183 184 // Sets the schemefully_same_ flag to false if other`'s scheme is 185 // cross-scheme to `this`. Schemes are considered cross-scheme if they're not 186 // compatible. Two schemes are compatible if they are either equal, or are 187 // both in {http, ws}, or are both in {https, wss}. 188 void MarkIfCrossScheme(const SchemefulSite& other); 189 190 // Represents the scheme and registrable domain of the site. The scheme should 191 // not be a WebSocket scheme; instead, ws is normalized to http, and 192 // wss is normalized to https upon construction. 193 SchemefulSite site_; 194 195 // Used to indicate if the SiteForCookies would be the same if computed 196 // schemefully. A schemeful computation means to take the scheme as well as 197 // the registrable_domain into account when determining same-siteness. 198 // See the class-level comment for more details on schemeless vs schemeful. 199 // 200 // True means to treat `this` as-is while false means that `this` should be 201 // treated as if it matches nothing i.e. IsNull() returns true. 202 // 203 // This value is important in the case where the SiteForCookies is being used 204 // to assess the first-partyness of a sub-frame in a document. 205 // 206 // For a SiteForCookies with !site_.opaque() this value starts as true and 207 // will only go false via MarkIfCrossScheme(), otherwise this value is 208 // irrelevant (For tests this value can also be modified by 209 // SetSchemefullySameForTesting()). 210 bool schemefully_same_ = false; 211 }; 212 213 } // namespace net 214 215 #endif // NET_COOKIES_SITE_FOR_COOKIES_H_ 216