// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/extras/sqlite/sqlite_persistent_cookie_store.h" #include <iterator> #include <map> #include <memory> #include <optional> #include <set> #include <tuple> #include <unordered_set> #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/synchronization/lock.h" #include "base/task/sequenced_task_runner.h" #include "base/thread_annotations.h" #include "base/time/time.h" #include "base/types/optional_ref.h" #include "base/values.h" #include "build/build_config.h" #include "crypto/sha2.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_constants.h" #include "net/cookies/cookie_util.h" #include "net/extras/sqlite/cookie_crypto_delegate.h" #include "net/extras/sqlite/sqlite_persistent_store_backend_base.h" #include "net/log/net_log.h" #include "net/log/net_log_values.h" #include "sql/error_delegate_util.h" #include "sql/meta_table.h" #include "sql/statement.h" #include "sql/transaction.h" #include "url/gurl.h" #include "url/third_party/mozilla/url_parse.h" Time; namespace { static constexpr int kHoursInOneWeek = …; static constexpr int kHoursInOneYear = …; base::Value::Dict CookieKeyedLoadNetLogParams( const std::string& key, net::NetLogCaptureMode capture_mode) { … } // Used to populate a histogram for problems when loading cookies. // // Please do not reorder or remove entries. New entries must be added to the // end of the list, just before COOKIE_LOAD_PROBLEM_LAST_ENTRY. enum CookieLoadProblem { … }; // Used to populate a histogram for problems when committing cookies. // // Please do not reorder or remove entries. New entries must be added to the // end of the list, just before COOKIE_COMMIT_PROBLEM_LAST_ENTRY. enum CookieCommitProblem { … }; void RecordCookieLoadProblem(CookieLoadProblem event) { … } void RecordCookieCommitProblem(CookieCommitProblem event) { … } // Records metrics around the age in hours of a cookie loaded from the store via // MakeCookiesFromSQLStatement for use by some browser context. void HistogramCookieAge(const net::CanonicalCookie& cookie) { … } } // namespace namespace net { base::TaskPriority GetCookieStoreBackgroundSequencePriority() { … } namespace { // Version number of the database. // // Version 24 - 2024/08/15 - https://crrev.com/c/5792044 // Version 23 - 2024/04/10 - https://crrev.com/c/5169630 // Version 22 - 2024/03/22 - https://crrev.com/c/5378176 // Version 21 - 2023/11/22 - https://crrev.com/c/5049032 // Version 20 - 2023/11/14 - https://crrev.com/c/5030577 // Version 19 - 2023/09/22 - https://crrev.com/c/4704672 // Version 18 - 2022/04/19 - https://crrev.com/c/3594203 // // Versions older than two years should be removed and marked as unsupported. // This was last done in February 2024. https://crrev.com/c/5300252 // Be sure to update SQLitePersistentCookieStoreTest.TestInvalidVersionRecovery // to test the latest unsupported version number. // // Unsupported versions: // Version 17 - 2022/01/25 - https://crrev.com/c/3416230 // Version 16 - 2021/09/10 - https://crrev.com/c/3152897 // Version 15 - 2021/07/01 - https://crrev.com/c/3001822 // Version 14 - 2021/02/23 - https://crrev.com/c/2036899 // Version 13 - 2020/10/28 - https://crrev.com/c/2505468 // Version 12 - 2019/11/20 - https://crrev.com/c/1898301 // Version 11 - 2019/04/17 - https://crrev.com/c/1570416 // Version 10 - 2018/02/13 - https://crrev.com/c/906675 // Version 9 - 2015/04/17 - https://codereview.chromium.org/1083623003 // Version 8 - 2015/02/23 - https://codereview.chromium.org/876973003 // Version 7 - 2013/12/16 - https://codereview.chromium.org/24734007 // Version 6 - 2013/04/23 - https://codereview.chromium.org/14208017 // Version 5 - 2011/12/05 - https://codereview.chromium.org/8533013 // Version 4 - 2009/09/01 - https://codereview.chromium.org/183021 // // Version 24 adds a SHA256 hash of the domain value to front of the the // encrypted_value. // // Version 23 adds the value for has_cross_site_ancestor and updates any // preexisting cookies with a source_scheme value of kUnset and a is_secure of // true to have a source_scheme value of kSecure. // // Version 22 adds one new field: "source_type". This reflects the source of // the last set/update to the cookie (unknown, http, script, other). Existing // cookies in the DB default to "unknown". // // Version 21 removes the is_same_party column. // // Version 20 changes the UNIQUE constraint to include the source_scheme and // source_port and begins to insert, update, and delete cookies based on their // source_scheme and source_port. // // Version 19 caps expires_utc to no more than 400 days in the future for all // stored cookies with has_expires. This is in compliance with section 7.2 of // draft-ietf-httpbis-rfc6265bis-12. // // Version 18 adds one new field: "last_update_utc" (if not 0 this represents // the last time the cookie was updated). This is distinct from creation_utc // which is carried forward when cookies are updated. // // Version 17 fixes crbug.com/1290841: Bug in V16 migration. // // Version 16 changes the unique constraint's order of columns to have // top_frame_site_key be after host_key. This allows us to use the internal // index created by the UNIQUE keyword without to load cookies by domain // without us needing to supply a top_frame_site_key. This is necessary because // CookieMonster tracks pending cookie loading tasks by host key only. // Version 16 also removes the DEFAULT value from several columns. // // Version 15 adds one new field: "top_frame_site_key" (if not empty then the // string is the scheme and site of the topmost-level frame the cookie was // created in). This field is deserialized into the cookie's partition key. // top_frame_site_key is *NOT* the site-for-cookies when the cookie was created. // In migrating, top_frame_site_key defaults to empty string. This change also // changes the uniqueness constraint on cookies to include the // top_frame_site_key as well. // // Version 14 just reads all encrypted cookies and re-writes them out again to // make sure the new encryption key is in use. This active migration only // happens on Windows, on other OS, this migration is a no-op. // // Version 13 adds two new fields: "source_port" (the port number of the source // origin, and "is_same_party" (boolean indicating whether the cookie had a // SameParty attribute). In migrating, source_port defaults to -1 // (url::PORT_UNSPECIFIED) for old entries for which the source port is unknown, // and is_same_party defaults to false. // // Version 12 adds a column for "source_scheme" to store whether the // cookie was set from a URL with a cryptographic scheme. // // Version 11 renames the "firstpartyonly" column to "samesite", and changes any // stored values of kCookieSameSiteNoRestriction into // kCookieSameSiteUnspecified to reflect the fact that those cookies were set // without a SameSite attribute specified. Support for a value of // kCookieSameSiteExtended for "samesite" was added, however, that value is now // deprecated and is mapped to CookieSameSite::UNSPECIFIED when loading from the // database. // // Version 10 removes the uniqueness constraint on the creation time (which // was not propagated up the stack and caused problems in // http://crbug.com/800414 and others). It replaces that constraint by a // constraint on (name, domain, path), which is spec-compliant (see // https://tools.ietf.org/html/rfc6265#section-5.3 step 11). Those fields // can then be used in place of the creation time for updating access // time and deleting cookies. // Version 10 also marks all booleans in the store with an "is_" prefix // to indicated their booleanness, as SQLite has no such concept. // // Version 9 adds a partial index to track non-persistent cookies. // Non-persistent cookies sometimes need to be deleted on startup. There are // frequently few or no non-persistent cookies, so the partial index allows the // deletion to be sped up or skipped, without having to page in the DB. // // Version 8 adds "first-party only" cookies. // // Version 7 adds encrypted values. Old values will continue to be used but // all new values written will be encrypted on selected operating systems. New // records read by old clients will simply get an empty cookie value while old // records read by new clients will continue to operate with the unencrypted // version. New and old clients alike will always write/update records with // what they support. // // Version 6 adds cookie priorities. This allows developers to influence the // order in which cookies are evicted in order to meet domain cookie limits. // // Version 5 adds the columns has_expires and is_persistent, so that the // database can store session cookies as well as persistent cookies. Databases // of version 5 are incompatible with older versions of code. If a database of // version 5 is read by older code, session cookies will be treated as normal // cookies. Currently, these fields are written, but not read anymore. // // In version 4, we migrated the time epoch. If you open the DB with an older // version on Mac or Linux, the times will look wonky, but the file will likely // be usable. On Windows version 3 and 4 are the same. // // Version 3 updated the database to include the last access time, so we can // expire them in decreasing order of use when we've reached the maximum // number of cookies. const int kCurrentVersionNumber = …; const int kCompatibleVersionNumber = …; } // namespace // This class is designed to be shared between any client thread and the // background task runner. It batches operations and commits them on a timer. // // SQLitePersistentCookieStore::Load is called to load all cookies. It // delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread // task to the background runner. This task calls Backend::ChainLoadCookies(), // which repeatedly posts itself to the BG runner to load each eTLD+1's cookies // in separate tasks. When this is complete, Backend::CompleteLoadOnIOThread is // posted to the client runner, which notifies the caller of // SQLitePersistentCookieStore::Load that the load is complete. // // If a priority load request is invoked via SQLitePersistentCookieStore:: // LoadCookiesForKey, it is delegated to Backend::LoadCookiesForKey, which posts // Backend::LoadKeyAndNotifyOnDBThread to the BG runner. That routine loads just // that single domain key (eTLD+1)'s cookies, and posts a Backend:: // CompleteLoadForKeyOnIOThread to the client runner to notify the caller of // SQLitePersistentCookieStore::LoadCookiesForKey that that load is complete. // // Subsequent to loading, mutations may be queued by any thread using // AddCookie, UpdateCookieAccessTime, and DeleteCookie. These are flushed to // disk on the BG runner every 30 seconds, 512 operations, or call to Flush(), // whichever occurs first. class SQLitePersistentCookieStore::Backend : public SQLitePersistentStoreBackendBase { … }; namespace { // Possible values for the 'priority' column. enum DBCookiePriority { … }; DBCookiePriority CookiePriorityToDBCookiePriority(CookiePriority value) { … } CookiePriority DBCookiePriorityToCookiePriority(DBCookiePriority value) { … } // Possible values for the 'samesite' column enum DBCookieSameSite { … }; DBCookieSameSite CookieSameSiteToDBCookieSameSite(CookieSameSite value) { … } CookieSameSite DBCookieSameSiteToCookieSameSite(DBCookieSameSite value) { … } // Possible values for the `source` column enum DBCookieSourceType { … }; DBCookieSourceType CookieSourceTypeToDBCookieSourceType( CookieSourceType value) { … } CookieSourceType DBCookieSourceTypeToCookieSourceType( DBCookieSourceType value) { … } CookieSourceScheme DBToCookieSourceScheme(int value) { … } // Increments a specified TimeDelta by the duration between this object's // constructor and destructor. Not thread safe. Multiple instances may be // created with the same delta instance as long as their lifetimes are nested. // The shortest lived instances have no impact. class IncrementTimeDelta { … }; bool CreateV20Schema(sql::Database* db) { … } bool CreateV21Schema(sql::Database* db) { … } bool CreateV22Schema(sql::Database* db) { … } bool CreateV23Schema(sql::Database* db) { … } // v24 schema is identical to v23 schema. bool CreateV24Schema(sql::Database* db) { … } } // namespace void SQLitePersistentCookieStore::Backend::Load( LoadedCallback loaded_callback) { … } void SQLitePersistentCookieStore::Backend::LoadCookiesForKey( base::optional_ref<const std::string> key, LoadedCallback loaded_callback) { … } void SQLitePersistentCookieStore::Backend::CryptoHasInitFromLoad( base::optional_ref<const std::string> key, LoadedCallback loaded_callback) { … } void SQLitePersistentCookieStore::Backend::LoadAndNotifyInBackground( base::optional_ref<const std::string> key, LoadedCallback loaded_callback) { … } void SQLitePersistentCookieStore::Backend::NotifyLoadCompleteInForeground( LoadedCallback loaded_callback, bool load_success) { … } bool SQLitePersistentCookieStore::Backend::CreateDatabaseSchema() { … } bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() { … } void SQLitePersistentCookieStore::Backend::ChainLoadCookies( LoadedCallback loaded_callback) { … } bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains( const std::set<std::string>& domains) { … } void SQLitePersistentCookieStore::Backend::DeleteTopFrameSiteKeys( const std::unordered_set<std::string>& top_frame_site_keys) { … } bool SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement( std::vector<std::unique_ptr<CanonicalCookie>>& cookies, sql::Statement& statement, std::unordered_set<std::string>& top_frame_site_keys_to_delete) { … } std::optional<int> SQLitePersistentCookieStore::Backend::DoMigrateDatabaseSchema() { … } void SQLitePersistentCookieStore::Backend::AddCookie( const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime( const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::Backend::DeleteCookie( const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::Backend::BatchOperation( PendingOperation::OperationType op, const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::Backend::DoCommit() { … } size_t SQLitePersistentCookieStore::Backend::GetQueueLengthForTesting() { … } void SQLitePersistentCookieStore::Backend::DeleteAllInList( const std::list<CookieOrigin>& cookies) { … } void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() { … } // TODO(crbug.com/40188414) Investigate including top_frame_site_key in the // WHERE clause. void SQLitePersistentCookieStore::Backend::BackgroundDeleteAllInList( const std::list<CookieOrigin>& cookies) { … } void SQLitePersistentCookieStore::Backend::FinishedLoadingCookies( LoadedCallback loaded_callback, bool success) { … } SQLitePersistentCookieStore::SQLitePersistentCookieStore( const base::FilePath& path, const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, bool restore_old_session_cookies, std::unique_ptr<CookieCryptoDelegate> crypto_delegate, bool enable_exclusive_access) : … { … } void SQLitePersistentCookieStore::DeleteAllInList( const std::list<CookieOrigin>& cookies) { … } void SQLitePersistentCookieStore::Load(LoadedCallback loaded_callback, const NetLogWithSource& net_log) { … } void SQLitePersistentCookieStore::LoadCookiesForKey( const std::string& key, LoadedCallback loaded_callback) { … } void SQLitePersistentCookieStore::AddCookie(const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::UpdateCookieAccessTime( const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::DeleteCookie(const CanonicalCookie& cc) { … } void SQLitePersistentCookieStore::SetForceKeepSessionState() { … } void SQLitePersistentCookieStore::SetBeforeCommitCallback( base::RepeatingClosure callback) { … } void SQLitePersistentCookieStore::Flush(base::OnceClosure callback) { … } size_t SQLitePersistentCookieStore::GetQueueLengthForTesting() { … } SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { … } void SQLitePersistentCookieStore::CompleteLoad( LoadedCallback callback, std::vector<std::unique_ptr<CanonicalCookie>> cookie_list) { … } void SQLitePersistentCookieStore::CompleteKeyedLoad( const std::string& key, LoadedCallback callback, std::vector<std::unique_ptr<CanonicalCookie>> cookie_list) { … } } // namespace net