Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: net/cookies/canonical_cookie.cc

Issue 2861063003: Remove dangerous CanonicalCookie::Create method. (Closed)
Patch Set: Incorporated all comments. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Portions of this code based on Mozilla: 5 // Portions of this code based on Mozilla:
6 // (netwerk/cookie/src/nsCookieService.cpp) 6 // (netwerk/cookie/src/nsCookieService.cpp)
7 /* ***** BEGIN LICENSE BLOCK ***** 7 /* ***** BEGIN LICENSE BLOCK *****
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9 * 9 *
10 * The contents of this file are subject to the Mozilla Public License Version 10 * The contents of this file are subject to the Mozilla Public License Version
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 // Determine the cookie domain to use for setting the specified cookie. 67 // Determine the cookie domain to use for setting the specified cookie.
68 bool GetCookieDomain(const GURL& url, 68 bool GetCookieDomain(const GURL& url,
69 const ParsedCookie& pc, 69 const ParsedCookie& pc,
70 std::string* result) { 70 std::string* result) {
71 std::string domain_string; 71 std::string domain_string;
72 if (pc.HasDomain()) 72 if (pc.HasDomain())
73 domain_string = pc.Domain(); 73 domain_string = pc.Domain();
74 return cookie_util::GetCookieDomainWithString(url, domain_string, result); 74 return cookie_util::GetCookieDomainWithString(url, domain_string, result);
75 } 75 }
76 76
77 std::string CanonPathWithString(const GURL& url,
78 const std::string& path_string) {
79 // The RFC says the path should be a prefix of the current URL path.
80 // However, Mozilla allows you to set any path for compatibility with
81 // broken websites. We unfortunately will mimic this behavior. We try
82 // to be generous and accept cookies with an invalid path attribute, and
83 // default the path to something reasonable.
84
85 // The path was supplied in the cookie, we'll take it.
86 if (!path_string.empty() && path_string[0] == '/')
87 return path_string;
88
89 // The path was not supplied in the cookie or invalid, we will default
90 // to the current URL path.
91 // """Defaults to the path of the request URL that generated the
92 // Set-Cookie response, up to, but not including, the
93 // right-most /."""
94 // How would this work for a cookie on /? We will include it then.
95 const std::string& url_path = url.path();
96
97 size_t idx = url_path.find_last_of('/');
98
99 // The cookie path was invalid or a single '/'.
100 if (idx == 0 || idx == std::string::npos)
101 return std::string("/");
102
103 // Return up to the rightmost '/'.
104 return url_path.substr(0, idx);
105 }
106
107 // Compares cookies using name, domain and path, so that "equivalent" cookies 77 // Compares cookies using name, domain and path, so that "equivalent" cookies
108 // (per RFC 2965) are equal to each other. 78 // (per RFC 2965) are equal to each other.
109 int PartialCookieOrdering(const CanonicalCookie& a, const CanonicalCookie& b) { 79 int PartialCookieOrdering(const CanonicalCookie& a, const CanonicalCookie& b) {
110 int diff = a.Name().compare(b.Name()); 80 int diff = a.Name().compare(b.Name());
111 if (diff != 0) 81 if (diff != 0)
112 return diff; 82 return diff;
113 83
114 diff = a.Domain().compare(b.Domain()); 84 diff = a.Domain().compare(b.Domain());
115 if (diff != 0) 85 if (diff != 0)
116 return diff; 86 return diff;
117 87
118 return a.Path().compare(b.Path()); 88 return a.Path().compare(b.Path());
119 } 89 }
120 90
121 } // namespace 91 } // namespace
122 92
123 CanonicalCookie::CanonicalCookie() 93 CanonicalCookie::CanonicalCookie()
124 : secure_(false), 94 : secure_(false),
125 httponly_(false) { 95 httponly_(false) {
126 } 96 }
127 97
128 CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default; 98 CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default;
129 99
130 CanonicalCookie::~CanonicalCookie() {} 100 CanonicalCookie::~CanonicalCookie() {}
131 101
132 // static 102 // static
133 std::string CanonicalCookie::CanonPath(const GURL& url, 103 std::string CanonicalCookie::CanonPathWithString(
134 const ParsedCookie& pc) { 104 const GURL& url,
135 std::string path_string; 105 const std::string& path_string) {
136 if (pc.HasPath()) 106 // The RFC says the path should be a prefix of the current URL path.
137 path_string = pc.Path(); 107 // However, Mozilla allows you to set any path for compatibility with
138 return CanonPathWithString(url, path_string); 108 // broken websites. We unfortunately will mimic this behavior. We try
109 // to be generous and accept cookies with an invalid path attribute, and
110 // default the path to something reasonable.
111
112 // The path was supplied in the cookie, we'll take it.
113 if (!path_string.empty() && path_string[0] == '/')
114 return path_string;
115
116 // The path was not supplied in the cookie or invalid, we will default
117 // to the current URL path.
118 // """Defaults to the path of the request URL that generated the
119 // Set-Cookie response, up to, but not including, the
120 // right-most /."""
121 // How would this work for a cookie on /? We will include it then.
122 const std::string& url_path = url.path();
123
124 size_t idx = url_path.find_last_of('/');
125
126 // The cookie path was invalid or a single '/'.
127 if (idx == 0 || idx == std::string::npos)
128 return std::string("/");
129
130 // Return up to the rightmost '/'.
131 return url_path.substr(0, idx);
139 } 132 }
140 133
141 // static 134 // static
142 Time CanonicalCookie::CanonExpiration(const ParsedCookie& pc, 135 Time CanonicalCookie::CanonExpiration(const ParsedCookie& pc,
143 const Time& current, 136 const Time& current,
144 const Time& server_time) { 137 const Time& server_time) {
145 // First, try the Max-Age attribute. 138 // First, try the Max-Age attribute.
146 uint64_t max_age = 0; 139 uint64_t max_age = 0;
147 if (pc.HasMaxAge() && 140 if (pc.HasMaxAge() &&
148 #ifdef COMPILER_MSVC 141 #ifdef COMPILER_MSVC
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 // Per 3.2.1 of "Deprecate modification of 'secure' cookies from non-secure 187 // Per 3.2.1 of "Deprecate modification of 'secure' cookies from non-secure
195 // origins", if the cookie's "secure-only-flag" is "true" and the requesting 188 // origins", if the cookie's "secure-only-flag" is "true" and the requesting
196 // URL does not have a secure scheme, the cookie should be thrown away. 189 // URL does not have a secure scheme, the cookie should be thrown away.
197 // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone 190 // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
198 if (parsed_cookie.IsSecure() && !url.SchemeIsCryptographic()) { 191 if (parsed_cookie.IsSecure() && !url.SchemeIsCryptographic()) {
199 VLOG(kVlogSetCookies) 192 VLOG(kVlogSetCookies)
200 << "Create() is trying to create a secure cookie from an insecure URL"; 193 << "Create() is trying to create a secure cookie from an insecure URL";
201 return nullptr; 194 return nullptr;
202 } 195 }
203 196
204 std::string cookie_path = CanonicalCookie::CanonPath(url, parsed_cookie); 197 std::string cookie_path = CanonPathWithString(
198 url, parsed_cookie.HasPath() ? parsed_cookie.Path() : std::string());
199
205 Time server_time(creation_time); 200 Time server_time(creation_time);
206 if (options.has_server_time()) 201 if (options.has_server_time())
207 server_time = options.server_time(); 202 server_time = options.server_time();
208 203
209 Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie, 204 Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie,
210 creation_time, 205 creation_time,
211 server_time); 206 server_time);
212 207
213 CookiePrefix prefix = CanonicalCookie::GetCookiePrefix(parsed_cookie.Name()); 208 CookiePrefix prefix = CanonicalCookie::GetCookiePrefix(parsed_cookie.Name());
214 bool is_cookie_valid = 209 bool is_cookie_valid =
215 CanonicalCookie::IsCookiePrefixValid(prefix, url, parsed_cookie); 210 CanonicalCookie::IsCookiePrefixValid(prefix, url, parsed_cookie);
216 CanonicalCookie::RecordCookiePrefixMetrics(prefix, is_cookie_valid); 211 CanonicalCookie::RecordCookiePrefixMetrics(prefix, is_cookie_valid);
217 if (!is_cookie_valid) { 212 if (!is_cookie_valid) {
218 VLOG(kVlogSetCookies) 213 VLOG(kVlogSetCookies)
219 << "Create() failed because the cookie violated prefix rules."; 214 << "Create() failed because the cookie violated prefix rules.";
220 return nullptr; 215 return nullptr;
221 } 216 }
222 217
223 return base::WrapUnique(new CanonicalCookie( 218 return base::WrapUnique(new CanonicalCookie(
224 parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path, 219 parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path,
225 creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(), 220 creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(),
226 parsed_cookie.IsHttpOnly(), parsed_cookie.SameSite(), 221 parsed_cookie.IsHttpOnly(), parsed_cookie.SameSite(),
227 parsed_cookie.Priority())); 222 parsed_cookie.Priority()));
228 } 223 }
229 224
230 // static 225 // static
231 std::unique_ptr<CanonicalCookie> CanonicalCookie::Create( 226 std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
232 const GURL& url,
233 const std::string& name,
234 const std::string& value,
235 const std::string& domain,
236 const std::string& path,
237 const base::Time& creation,
238 const base::Time& expiration,
239 bool secure,
240 bool http_only,
241 CookieSameSite same_site,
242 CookiePriority priority) {
243 // Expect valid attribute tokens and values, as defined by the ParsedCookie
244 // logic, otherwise don't create the cookie.
245 std::string parsed_name = ParsedCookie::ParseTokenString(name);
246 if (parsed_name != name)
247 return nullptr;
248 std::string parsed_value = ParsedCookie::ParseValueString(value);
249 if (parsed_value != value)
250 return nullptr;
251
252 std::string parsed_domain = ParsedCookie::ParseValueString(domain);
253 if (parsed_domain != domain)
254 return nullptr;
255 std::string cookie_domain;
256 if (!cookie_util::GetCookieDomainWithString(url, parsed_domain,
257 &cookie_domain)) {
258 return nullptr;
259 }
260
261 if (secure && !url.SchemeIsCryptographic())
262 return nullptr;
263
264 std::string parsed_path = ParsedCookie::ParseValueString(path);
265 if (parsed_path != path)
266 return nullptr;
267
268 std::string cookie_path = CanonPathWithString(url, parsed_path);
269 // Expect that the path was either not specified (empty), or is valid.
270 if (!parsed_path.empty() && cookie_path != parsed_path)
271 return nullptr;
272 // Canonicalize path again to make sure it escapes characters as needed.
273 url::Component path_component(0, cookie_path.length());
274 url::RawCanonOutputT<char> canon_path;
275 url::Component canon_path_component;
276 url::CanonicalizePath(cookie_path.data(), path_component, &canon_path,
277 &canon_path_component);
278 cookie_path = std::string(canon_path.data() + canon_path_component.begin,
279 canon_path_component.len);
280
281 return base::WrapUnique(new CanonicalCookie(
282 parsed_name, parsed_value, cookie_domain, cookie_path, creation,
283 expiration, creation, secure, http_only, same_site, priority));
284 }
285
286 // static
287 std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
288 const std::string& name, 227 const std::string& name,
289 const std::string& value, 228 const std::string& value,
290 const std::string& domain, 229 const std::string& domain,
291 const std::string& path, 230 const std::string& path,
292 const base::Time& creation, 231 const base::Time& creation,
293 const base::Time& expiration, 232 const base::Time& expiration,
294 const base::Time& last_access, 233 const base::Time& last_access,
295 bool secure, 234 bool secure,
296 bool http_only, 235 bool http_only,
297 CookieSameSite same_site, 236 CookieSameSite same_site,
298 CookiePriority priority) { 237 CookiePriority priority) {
238 DCHECK(!name.empty());
239 DCHECK(!path.empty());
240
299 return base::WrapUnique( 241 return base::WrapUnique(
300 new CanonicalCookie(name, value, domain, path, creation, expiration, 242 new CanonicalCookie(name, value, domain, path, creation, expiration,
301 last_access, secure, http_only, same_site, priority)); 243 last_access, secure, http_only, same_site, priority));
302 } 244 }
303 245
304 bool CanonicalCookie::IsEquivalentForSecureCookieMatching( 246 bool CanonicalCookie::IsEquivalentForSecureCookieMatching(
305 const CanonicalCookie& ecc) const { 247 const CanonicalCookie& ecc) const {
306 return (name_ == ecc.Name() && (ecc.IsDomainMatch(DomainWithoutDot()) || 248 return (name_ == ecc.Name() && (ecc.IsDomainMatch(DomainWithoutDot()) ||
307 IsDomainMatch(ecc.DomainWithoutDot())) && 249 IsDomainMatch(ecc.DomainWithoutDot())) &&
308 ecc.IsOnPath(Path())); 250 ecc.IsOnPath(Path()));
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 return true; 463 return true;
522 } 464 }
523 465
524 std::string CanonicalCookie::DomainWithoutDot() const { 466 std::string CanonicalCookie::DomainWithoutDot() const {
525 if (domain_.empty() || domain_[0] != '.') 467 if (domain_.empty() || domain_[0] != '.')
526 return domain_; 468 return domain_;
527 return domain_.substr(1); 469 return domain_.substr(1);
528 } 470 }
529 471
530 } // namespace net 472 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698