From 4d222df50a8dfaaabb31e9f2c5070c4db5ba8fd5 Mon Sep 17 00:00:00 2001 From: Francois Marier Date: Fri, 8 Mar 2019 19:13:46 -0800 Subject: [PATCH] Set a limit on cookie expiration (fixes brave/brave-browser#3443) The client-side cookie (i.e. document.cookie API) expiry limit is based off of the limit set by both Safari and Firefox: https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/ https://groups.google.com/forum/#!msg/mozilla.dev.platform/lECBPeiGTy4/cPP52vyZAwAJ whereas the server-side cookie (i.e. Set-Cookie header) limit was picked to avoid interfering in a noticeable way with user logins. --- .../brave_canonical_cookie_unittest.cc | 97 +++++++++++++++++++ chromium_src/net/cookies/canonical_cookie.cc | 28 ++++++ patches/net-cookies-canonical_cookie.cc.patch | 18 ++++ test/BUILD.gn | 1 + 4 files changed, 144 insertions(+) create mode 100644 chromium_src/net/cookies/brave_canonical_cookie_unittest.cc create mode 100644 chromium_src/net/cookies/canonical_cookie.cc create mode 100644 patches/net-cookies-canonical_cookie.cc.patch diff --git a/chromium_src/net/cookies/brave_canonical_cookie_unittest.cc b/chromium_src/net/cookies/brave_canonical_cookie_unittest.cc new file mode 100644 index 000000000000..bce02a254148 --- /dev/null +++ b/chromium_src/net/cookies/brave_canonical_cookie_unittest.cc @@ -0,0 +1,97 @@ +/* Copyright (c) 2019 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "net/cookies/canonical_cookie.h" + +#include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_options.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +static const std::string cookie_line1 = + "test1=yes; expires=Fri, 31 Dec 9999 23:59:59 GMT"; +static const std::string cookie_line2 = + "test2=yes; max-age=630720000"; // 20 years +static const std::string cookie_line3 = + "test3=yes; max-age=630720000; expires=Fri, 31 Dec 9999 23:59:59 GMT"; +static const std::string cookie_line4 = + "test4=yes; max-age=172800"; // 2 days +static const std::string cookie_line5 = + "test5=yes; httponly; expires=Fri, 31 Dec 9999 23:59:59 GMT"; + +namespace net { + +TEST(BraveCanonicalCookieTest, ClientSide) { + using base::TimeDelta; + + GURL url("https://www.example.com/test"); + base::Time creation_time = base::Time::Now(); + CookieOptions options; + + std::unique_ptr cookie( + CanonicalCookie::Create(url, cookie_line1, creation_time, options)); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(8)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(6)); + + cookie = CanonicalCookie::Create(url, cookie_line2, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(8)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(6)); + + cookie = CanonicalCookie::Create(url, cookie_line3, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(8)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(6)); + + // Short-lived cookies get to keep their shorter expiration. + cookie = CanonicalCookie::Create(url, cookie_line4, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(3)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(1)); + + // Cookies with 'httponly' can't be set using the document.cookie API. + cookie = CanonicalCookie::Create(url, cookie_line5, creation_time, options); + EXPECT_FALSE(cookie.get()); +} + +TEST(BraveCanonicalCookieTest, ServerSide) { + using base::TimeDelta; + + GURL url("https://www.example.com/test"); + base::Time creation_time = base::Time::Now(); + CookieOptions options; + options.set_include_httponly(); + + std::unique_ptr cookie( + CanonicalCookie::Create(url, cookie_line1, creation_time, options)); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*7)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*5)); + + cookie = CanonicalCookie::Create(url, cookie_line2, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*7)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*5)); + + cookie = CanonicalCookie::Create(url, cookie_line3, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*7)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*5)); + + // Short-lived cookies get to keep their shorter expiration. + cookie = CanonicalCookie::Create(url, cookie_line4, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(3)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(1)); + + // HTTP cookies with 'httponly' work as expected. + cookie = CanonicalCookie::Create(url, cookie_line5, creation_time, options); + EXPECT_TRUE(cookie.get()); + EXPECT_LT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*7)); + EXPECT_GT(cookie->ExpiryDate(), creation_time + TimeDelta::FromDays(30*5)); +} + +} // namespace diff --git a/chromium_src/net/cookies/canonical_cookie.cc b/chromium_src/net/cookies/canonical_cookie.cc new file mode 100644 index 000000000000..0c9e0da016b6 --- /dev/null +++ b/chromium_src/net/cookies/canonical_cookie.cc @@ -0,0 +1,28 @@ +/* Copyright (c) 2019 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "net/cookies/canonical_cookie.h" +#include "net/cookies/parsed_cookie.h" + +namespace { + +const base::TimeDelta kMaxClientSideExpiration = base::TimeDelta::FromDays(7); +const base::TimeDelta kMaxServerSideExpiration = + base::TimeDelta::FromDays(30*6); // 6 months + +base::Time BraveCanonExpiration(const net::ParsedCookie& pc, + const base::Time& current, + const base::Time& server_time, + const bool is_from_http) { + const base::Time max_expiration = current + + (is_from_http ? kMaxServerSideExpiration : kMaxClientSideExpiration); + + return std::min(net::CanonicalCookie::CanonExpiration(pc, current, server_time), + max_expiration); +} + +} // namespace + +#include "../../../../net/cookies/canonical_cookie.cc" diff --git a/patches/net-cookies-canonical_cookie.cc.patch b/patches/net-cookies-canonical_cookie.cc.patch new file mode 100644 index 000000000000..eea2427fd410 --- /dev/null +++ b/patches/net-cookies-canonical_cookie.cc.patch @@ -0,0 +1,18 @@ +diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc +index 91611ac4171c19a031044ae6b1459acce246d427..c0636088e332f61c9ee8e6ed07f210fa8e47de58 100644 +--- a/net/cookies/canonical_cookie.cc ++++ b/net/cookies/canonical_cookie.cc +@@ -228,9 +228,10 @@ std::unique_ptr CanonicalCookie::Create( + server_time = options.server_time(); + + DCHECK(!creation_time.is_null()); +- Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie, +- creation_time, +- server_time); ++ Time cookie_expires = BraveCanonExpiration(parsed_cookie, ++ creation_time, ++ server_time, ++ !options.exclude_httponly()); + + CookiePrefix prefix = GetCookiePrefix(parsed_cookie.Name()); + bool is_cookie_valid = IsCookiePrefixValid(prefix, url, parsed_cookie); diff --git a/test/BUILD.gn b/test/BUILD.gn index 81553601d027..33196e3e6618 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -67,6 +67,7 @@ test("brave_unit_tests") { "//brave/chromium_src/components/search_engines/brave_template_url_prepopulate_data_unittest.cc", "//brave/chromium_src/components/search_engines/brave_template_url_service_util_unittest.cc", "//brave/chromium_src/components/version_info/brave_version_info_unittest.cc", + "//brave/chromium_src/net/cookies/brave_canonical_cookie_unittest.cc", "//brave/common/brave_content_client_unittest.cc", "//brave/common/importer/brave_mock_importer_bridge.cc", "//brave/common/importer/brave_mock_importer_bridge.h",