Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "net/base/isolation_info.h" |
| 6 | |
Hans Wennborg | 0924470b | 2020-04-27 21:08:05 | [diff] [blame] | 7 | #include "base/check_op.h" |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 8 | |
| 9 | namespace net { |
| 10 | |
| 11 | namespace { |
| 12 | |
| 13 | // Checks that |origin| is consistent with |site_for_cookies|. |
| 14 | bool ValidateSameSite(const url::Origin& origin, |
| 15 | const SiteForCookies& site_for_cookies) { |
| 16 | // If not sending SameSite cookies, or sending them for a non-scheme, consider |
| 17 | // all origins consistent. Note that SiteForCookies should never be created |
| 18 | // for websocket schemes for valid navigations, since frames can't be |
| 19 | // navigated to those schemes. |
| 20 | if (site_for_cookies.IsNull() || |
| 21 | (site_for_cookies.scheme() != url::kHttpScheme && |
| 22 | site_for_cookies.scheme() != url::kHttpsScheme)) { |
| 23 | return true; |
| 24 | } |
| 25 | |
| 26 | // Shouldn't send cookies for opaque origins. |
| 27 | if (origin.opaque()) |
| 28 | return false; |
| 29 | |
| 30 | // TODO(https://crbug.com/1060631): GetURL() is expensive. Maybe make a |
| 31 | // version of IsFirstParty that works on origins? |
| 32 | return site_for_cookies.IsFirstParty(origin.GetURL()); |
| 33 | } |
| 34 | |
| 35 | // Checks if these values are consistent. See IsolationInfo::Create() for |
| 36 | // descriptions of consistent sets of values. Also allows values used by the |
| 37 | // 0-argument constructor. Additionally, |opaque_and_non_transient| can only be |
| 38 | // true if both origins are opaque and |site_for_cookies| is null. |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 39 | bool IsConsistent(IsolationInfo::RequestType request_type, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 40 | const base::Optional<url::Origin>& top_frame_origin, |
| 41 | const base::Optional<url::Origin>& frame_origin, |
| 42 | const SiteForCookies& site_for_cookies, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 43 | bool opaque_and_non_transient, |
| 44 | base::Optional<std::set<SchemefulSite>> party_context) { |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 45 | // Check for the default-constructed case. |
| 46 | if (!top_frame_origin) { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 47 | return request_type == IsolationInfo::RequestType::kOther && |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 48 | !frame_origin && site_for_cookies.IsNull() && |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 49 | !opaque_and_non_transient && !party_context; |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 50 | } |
| 51 | |
| 52 | // |frame_origin| may only be nullopt is |top_frame_origin| is as well. |
| 53 | if (!frame_origin) |
| 54 | return false; |
| 55 | |
| 56 | // As long as there is a |top_frame_origin|, |site_for_cookies| must be |
| 57 | // consistent with the |top_frame_origin|. |
| 58 | if (!ValidateSameSite(*top_frame_origin, site_for_cookies)) |
| 59 | return false; |
| 60 | |
| 61 | if (opaque_and_non_transient) { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 62 | return (request_type == IsolationInfo::RequestType::kOther && |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 63 | top_frame_origin->opaque() && top_frame_origin == frame_origin && |
| 64 | site_for_cookies.IsNull()); |
| 65 | } |
| 66 | |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 67 | switch (request_type) { |
| 68 | case IsolationInfo::RequestType::kMainFrame: |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 69 | // TODO(https://crbug.com/1056706): Check that |top_frame_origin| and |
| 70 | // |frame_origin| are the same, once the ViewSource code creates a |
| 71 | // consistent IsolationInfo object. |
| 72 | // |
| 73 | // TODO(https://crbug.com/1060631): Once CreatePartial() is removed, check |
| 74 | // if SiteForCookies is non-null if the scheme is HTTP or HTTPS. |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 75 | // |
| 76 | // TODO(https://crbug.com/1151947): Once CreatePartial() is removed, check |
| 77 | // if party_context is non-null and empty. |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 78 | return true; |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 79 | case IsolationInfo::RequestType::kSubFrame: |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 80 | // For subframe navigations, the subframe's origin may not be consistent |
| 81 | // with the SiteForCookies, so SameSite cookies may be sent if there's a |
| 82 | // redirect to main frames site. |
| 83 | return true; |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 84 | case IsolationInfo::RequestType::kOther: |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 85 | // SiteForCookies must consistent with the frame origin as well for |
| 86 | // subresources. |
| 87 | return ValidateSameSite(*frame_origin, site_for_cookies); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | } // namespace |
| 92 | |
| 93 | IsolationInfo::IsolationInfo() |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 94 | : IsolationInfo(RequestType::kOther, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 95 | base::nullopt, |
| 96 | base::nullopt, |
| 97 | SiteForCookies(), |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 98 | false /* opaque_and_non_transient */, |
| 99 | base::nullopt) {} |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 100 | |
| 101 | IsolationInfo::IsolationInfo(const IsolationInfo&) = default; |
| 102 | IsolationInfo::IsolationInfo(IsolationInfo&&) = default; |
| 103 | IsolationInfo::~IsolationInfo() = default; |
| 104 | IsolationInfo& IsolationInfo::operator=(const IsolationInfo&) = default; |
| 105 | IsolationInfo& IsolationInfo::operator=(IsolationInfo&&) = default; |
| 106 | |
| 107 | IsolationInfo IsolationInfo::CreateForInternalRequest( |
| 108 | const url::Origin& top_frame_origin) { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 109 | return IsolationInfo(RequestType::kOther, top_frame_origin, top_frame_origin, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 110 | SiteForCookies::FromOrigin(top_frame_origin), |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 111 | false /* opaque_and_non_transient */, |
| 112 | std::set<SchemefulSite>() /* party_context */); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | IsolationInfo IsolationInfo::CreateTransient() { |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 116 | url::Origin opaque_origin; |
| 117 | return IsolationInfo(RequestType::kOther, opaque_origin, opaque_origin, |
| 118 | SiteForCookies(), false /* opaque_and_non_transient */, |
| 119 | base::nullopt /* party_context */); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | IsolationInfo IsolationInfo::CreateOpaqueAndNonTransient() { |
| 123 | url::Origin opaque_origin; |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 124 | return IsolationInfo(RequestType::kOther, opaque_origin, opaque_origin, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 125 | SiteForCookies(), true /* opaque_and_non_transient */, |
| 126 | base::nullopt /* party_context */); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 127 | } |
| 128 | |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 129 | IsolationInfo IsolationInfo::Create( |
| 130 | RequestType request_type, |
| 131 | const url::Origin& top_frame_origin, |
| 132 | const url::Origin& frame_origin, |
| 133 | const SiteForCookies& site_for_cookies, |
| 134 | base::Optional<std::set<SchemefulSite>> party_context) { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 135 | return IsolationInfo(request_type, top_frame_origin, frame_origin, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 136 | site_for_cookies, false /* opaque_and_non_transient */, |
| 137 | std::move(party_context)); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | IsolationInfo IsolationInfo::CreatePartial( |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 141 | RequestType request_type, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 142 | const net::NetworkIsolationKey& network_isolation_key) { |
| 143 | if (!network_isolation_key.IsFullyPopulated()) |
| 144 | return IsolationInfo(); |
| 145 | |
Matt Menke | f8d36fd | 2020-11-20 03:56:13 | [diff] [blame] | 146 | // TODO(https://crbug.com/1148927): Use null origins in this case. |
| 147 | url::Origin top_frame_origin = |
| 148 | network_isolation_key.GetTopFrameSite()->site_as_origin_; |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 149 | url::Origin frame_origin; |
Matt Menke | e6e4f39 | 2020-10-08 11:41:29 | [diff] [blame] | 150 | if (network_isolation_key.GetFrameSite().has_value()) { |
Matt Menke | f8d36fd | 2020-11-20 03:56:13 | [diff] [blame] | 151 | frame_origin = network_isolation_key.GetFrameSite()->site_as_origin_; |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 152 | } else if (request_type == RequestType::kMainFrame) { |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 153 | frame_origin = top_frame_origin; |
| 154 | } else { |
| 155 | frame_origin = url::Origin(); |
| 156 | } |
| 157 | |
| 158 | bool opaque_and_non_transient = top_frame_origin.opaque() && |
| 159 | frame_origin.opaque() && |
| 160 | !network_isolation_key.IsTransient(); |
| 161 | |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 162 | return IsolationInfo(request_type, top_frame_origin, frame_origin, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 163 | SiteForCookies(), opaque_and_non_transient, |
| 164 | base::nullopt /* party_context */); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 165 | } |
| 166 | |
| 167 | base::Optional<IsolationInfo> IsolationInfo::CreateIfConsistent( |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 168 | RequestType request_type, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 169 | const base::Optional<url::Origin>& top_frame_origin, |
| 170 | const base::Optional<url::Origin>& frame_origin, |
| 171 | const SiteForCookies& site_for_cookies, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 172 | bool opaque_and_non_transient, |
| 173 | base::Optional<std::set<SchemefulSite>> party_context) { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 174 | if (!IsConsistent(request_type, top_frame_origin, frame_origin, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 175 | site_for_cookies, opaque_and_non_transient, |
| 176 | party_context)) { |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 177 | return base::nullopt; |
| 178 | } |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 179 | return IsolationInfo(request_type, top_frame_origin, frame_origin, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 180 | site_for_cookies, opaque_and_non_transient, |
| 181 | std::move(party_context)); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | IsolationInfo IsolationInfo::CreateForRedirect( |
| 185 | const url::Origin& new_origin) const { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 186 | if (request_type_ == RequestType::kOther) |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 187 | return *this; |
| 188 | |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 189 | if (request_type_ == RequestType::kSubFrame) { |
| 190 | return IsolationInfo(request_type_, top_frame_origin_, new_origin, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 191 | site_for_cookies_, opaque_and_non_transient_, |
| 192 | party_context_); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 193 | } |
| 194 | |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 195 | DCHECK_EQ(RequestType::kMainFrame, request_type_); |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 196 | DCHECK(!party_context_ || party_context_->empty()); |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 197 | return IsolationInfo(request_type_, new_origin, new_origin, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 198 | SiteForCookies::FromOrigin(new_origin), |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 199 | opaque_and_non_transient_, party_context_); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | bool IsolationInfo::IsEqualForTesting(const IsolationInfo& other) const { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 203 | return (request_type_ == other.request_type_ && |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 204 | top_frame_origin_ == other.top_frame_origin_ && |
| 205 | frame_origin_ == other.frame_origin_ && |
| 206 | network_isolation_key_ == other.network_isolation_key_ && |
| 207 | opaque_and_non_transient_ == other.opaque_and_non_transient_ && |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 208 | site_for_cookies_.IsEquivalent(other.site_for_cookies_) && |
| 209 | party_context_ == other.party_context_); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | IsolationInfo::IsolationInfo( |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 213 | RequestType request_type, |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 214 | const base::Optional<url::Origin>& top_frame_origin, |
| 215 | const base::Optional<url::Origin>& frame_origin, |
| 216 | const SiteForCookies& site_for_cookies, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 217 | bool opaque_and_non_transient, |
| 218 | base::Optional<std::set<SchemefulSite>> party_context) |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 219 | : request_type_(request_type), |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 220 | top_frame_origin_(top_frame_origin), |
| 221 | frame_origin_(frame_origin), |
| 222 | network_isolation_key_( |
Matt Menke | f8d36fd | 2020-11-20 03:56:13 | [diff] [blame] | 223 | !top_frame_origin |
| 224 | ? NetworkIsolationKey() |
| 225 | : NetworkIsolationKey(SchemefulSite(*top_frame_origin), |
| 226 | SchemefulSite(*frame_origin), |
| 227 | opaque_and_non_transient)), |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 228 | site_for_cookies_(site_for_cookies), |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 229 | opaque_and_non_transient_(opaque_and_non_transient), |
| 230 | party_context_(party_context.has_value() && |
| 231 | party_context->size() > kPartyContextMaxSize |
| 232 | ? base::nullopt |
| 233 | : party_context) { |
shivanigithub | 4e78015f59 | 2020-10-21 13:26:23 | [diff] [blame] | 234 | DCHECK(IsConsistent(request_type_, top_frame_origin_, frame_origin_, |
Shuran Huang | 0e0aaa5 | 2020-12-02 22:24:54 | [diff] [blame] | 235 | site_for_cookies_, opaque_and_non_transient_, |
| 236 | party_context_)); |
Matt Menke | 3ab9c7b | 2020-04-01 22:39:57 | [diff] [blame] | 237 | } |
| 238 | |
| 239 | } // namespace net |