1 // Copyright 2017 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 #ifndef COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_PASSWORD_PROTECTION_SERVICE_H_ 6 #define COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_PASSWORD_PROTECTION_SERVICE_H_ 7 8 #include <set> 9 #include <unordered_map> 10 11 #include "base/callback.h" 12 #include "base/feature_list.h" 13 #include "base/gtest_prod_util.h" 14 #include "base/macros.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/scoped_observer.h" 18 #include "base/task/cancelable_task_tracker.h" 19 #include "base/values.h" 20 #include "build/build_config.h" 21 #include "components/history/core/browser/history_service.h" 22 #include "components/history/core/browser/history_service_observer.h" 23 #include "components/password_manager/core/browser/password_manager_metrics_util.h" 24 #include "components/password_manager/core/browser/password_reuse_detector.h" 25 #include "components/safe_browsing/buildflags.h" 26 #include "components/safe_browsing/content/common/safe_browsing.mojom.h" 27 #include "components/safe_browsing/content/password_protection/metrics_util.h" 28 #include "components/safe_browsing/core/browser/referrer_chain_provider.h" 29 #include "components/safe_browsing/core/common/safe_browsing_prefs.h" 30 #include "components/safe_browsing/core/db/v4_protocol_manager_util.h" 31 #include "components/safe_browsing/core/proto/csd.pb.h" 32 #include "components/sessions/core/session_id.h" 33 #include "components/signin/public/identity_manager/account_info.h" 34 #include "mojo/public/cpp/bindings/remote.h" 35 #include "services/network/public/cpp/shared_url_loader_factory.h" 36 #include "services/service_manager/public/cpp/interface_provider.h" 37 #include "third_party/protobuf/src/google/protobuf/repeated_field.h" 38 39 namespace content { 40 class WebContents; 41 class NavigationHandle; 42 } 43 44 namespace policy { 45 class BrowserPolicyConnector; 46 } 47 48 class GURL; 49 class HostContentSettingsMap; 50 51 namespace safe_browsing { 52 53 class PasswordProtectionNavigationThrottle; 54 class PasswordProtectionRequest; 55 class SafeBrowsingDatabaseManager; 56 57 using ReusedPasswordAccountType = 58 LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordAccountType; 59 using ReusedPasswordType = 60 LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType; 61 using password_manager::metrics_util::PasswordType; 62 63 // Manage password protection pings and verdicts. There is one instance of this 64 // class per profile. Therefore, every PasswordProtectionService instance is 65 // associated with a unique HistoryService instance and a unique 66 // HostContentSettingsMap instance. 67 class PasswordProtectionService : public history::HistoryServiceObserver { 68 public: 69 PasswordProtectionService( 70 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, 71 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, 72 history::HistoryService* history_service); 73 74 ~PasswordProtectionService() override; 75 GetWeakPtr()76 base::WeakPtr<PasswordProtectionService> GetWeakPtr() { 77 return weak_factory_.GetWeakPtr(); 78 } 79 80 // Looks up |settings| to find the cached verdict response. If verdict is not 81 // available or is expired, return VERDICT_TYPE_UNSPECIFIED. Can be called on 82 // any thread. 83 virtual LoginReputationClientResponse::VerdictType GetCachedVerdict( 84 const GURL& url, 85 LoginReputationClientRequest::TriggerType trigger_type, 86 ReusedPasswordAccountType password_type, 87 LoginReputationClientResponse* out_response); 88 89 // Stores |verdict| in |settings| based on its |trigger_type|, |url|, 90 // reused |password_type|, |verdict| and |receive_time|. 91 virtual void CacheVerdict( 92 const GURL& url, 93 LoginReputationClientRequest::TriggerType trigger_type, 94 ReusedPasswordAccountType password_type, 95 const LoginReputationClientResponse& verdict, 96 const base::Time& receive_time); 97 98 // Creates an instance of PasswordProtectionRequest and call Start() on that 99 // instance. This function also insert this request object in |requests_| for 100 // record keeping. 101 void StartRequest( 102 content::WebContents* web_contents, 103 const GURL& main_frame_url, 104 const GURL& password_form_action, 105 const GURL& password_form_frame_url, 106 const std::string& username, 107 PasswordType password_type, 108 const std::vector<password_manager::MatchingReusedCredential>& 109 matching_reused_credentials, 110 LoginReputationClientRequest::TriggerType trigger_type, 111 bool password_field_exists); 112 113 #if defined(ON_FOCUS_PING_ENABLED) 114 virtual void MaybeStartPasswordFieldOnFocusRequest( 115 content::WebContents* web_contents, 116 const GURL& main_frame_url, 117 const GURL& password_form_action, 118 const GURL& password_form_frame_url, 119 const std::string& hosted_domain); 120 #endif 121 122 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED) 123 virtual void MaybeStartProtectedPasswordEntryRequest( 124 content::WebContents* web_contents, 125 const GURL& main_frame_url, 126 const std::string& username, 127 PasswordType password_type, 128 const std::vector<password_manager::MatchingReusedCredential>& 129 matching_reused_credentials, 130 bool password_field_exists); 131 #endif 132 133 #if defined(SYNC_PASSWORD_REUSE_WARNING_ENABLED) 134 // Records a Chrome Sync event that sync password reuse was detected. 135 virtual void MaybeLogPasswordReuseDetectedEvent( 136 content::WebContents* web_contents) = 0; 137 138 // If we want to show password reuse modal warning. 139 bool ShouldShowModalWarning( 140 LoginReputationClientRequest::TriggerType trigger_type, 141 ReusedPasswordAccountType password_type, 142 LoginReputationClientResponse::VerdictType verdict_type); 143 144 // Shows modal warning dialog on the current |web_contents| and pass the 145 // |verdict_token| to callback of this dialog. 146 virtual void ShowModalWarning( 147 content::WebContents* web_contents, 148 RequestOutcome outcome, 149 LoginReputationClientResponse::VerdictType verdict_type, 150 const std::string& verdict_token, 151 ReusedPasswordAccountType password_type) = 0; 152 153 // Shows chrome://reset-password interstitial. 154 virtual void ShowInterstitial(content::WebContents* web_contens, 155 ReusedPasswordAccountType password_type) = 0; 156 #endif 157 158 // The following functions are disabled on Android, because enterprise reporting 159 // extension is not supported. 160 #if !defined(OS_ANDROID) 161 // Triggers the safeBrowsingPrivate.OnPolicySpecifiedPasswordReuseDetected. 162 virtual void MaybeReportPasswordReuseDetected( 163 content::WebContents* web_contents, 164 const std::string& username, 165 PasswordType password_type, 166 bool is_phishing_url) = 0; 167 168 // Called when a protected password change is detected. Must be called on 169 // UI thread. 170 virtual void ReportPasswordChanged() = 0; 171 #endif 172 173 #if defined(SYNC_PASSWORD_REUSE_WARNING_ENABLED) 174 virtual void UpdateSecurityState(safe_browsing::SBThreatType threat_type, 175 ReusedPasswordAccountType password_type, 176 content::WebContents* web_contents) = 0; 177 #endif 178 179 scoped_refptr<SafeBrowsingDatabaseManager> database_manager(); 180 181 // Safe Browsing backend cannot get a reliable reputation of a URL if 182 // (1) URL is not valid 183 // (2) URL doesn't have http or https scheme 184 // (3) It maps to a local host. 185 // (4) Its hostname is an IP Address in an IANA-reserved range. 186 // (5) Its hostname is a not-yet-assigned by ICANN gTLD. 187 // (6) Its hostname is a dotless domain. 188 static bool CanGetReputationOfURL(const GURL& url); 189 190 // If user has clicked through any Safe Browsing interstitial on this given 191 // |web_contents|. 192 virtual bool UserClickedThroughSBInterstitial( 193 content::WebContents* web_contents) = 0; 194 195 // Called when a new navigation is starting. Create throttle if there is a 196 // pending sync password reuse ping or if there is a modal warning dialog 197 // showing in the corresponding web contents. 198 std::unique_ptr<PasswordProtectionNavigationThrottle> 199 MaybeCreateNavigationThrottle(content::NavigationHandle* navigation_handle); 200 201 // Returns if the warning UI is enabled. 202 bool IsWarningEnabled(ReusedPasswordAccountType password_type); 203 204 // Returns the pref value of password protection warning trigger. 205 virtual PasswordProtectionTrigger GetPasswordProtectionWarningTriggerPref( 206 ReusedPasswordAccountType password_type) const = 0; 207 208 // If |url| matches Safe Browsing whitelist domains, password protection 209 // change password URL, or password protection login URLs in the enterprise 210 // policy. 211 virtual bool IsURLWhitelistedForPasswordEntry( 212 const GURL& url, 213 RequestOutcome* reason) const = 0; 214 215 // Persist the phished saved password credential in the "compromised 216 // credentials" table. Calls the password store to add a row for each 217 // MatchingReusedCredential where the phished saved password is used on. 218 virtual void PersistPhishedSavedPasswordCredential( 219 const std::vector<password_manager::MatchingReusedCredential>& 220 matching_reused_credentials) = 0; 221 222 // Converts from password::metrics_util::PasswordType to 223 // LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType. 224 static ReusedPasswordType GetPasswordProtectionReusedPasswordType( 225 PasswordType password_type); 226 227 // Converts from password_manager::metrics_util::PasswordType 228 // to PasswordReuseEvent::ReusedPasswordAccountType. |username| is only 229 // used if |password_type| is OTHER_GAIA_PASSWORD because it needs to be 230 // compared to the list of signed in accounts. 231 ReusedPasswordAccountType GetPasswordProtectionReusedPasswordAccountType( 232 PasswordType password_type, 233 const std::string& username) const; 234 235 // Converts from ReusedPasswordAccountType to 236 // password_manager::metrics_util::PasswordType. 237 static PasswordType ConvertReusedPasswordAccountTypeToPasswordType( 238 ReusedPasswordAccountType password_type); 239 240 // If we can send ping for this type of reused password. 241 bool IsSupportedPasswordTypeForPinging(PasswordType password_type) const; 242 243 // If we can show modal warning for this type of reused password. 244 bool IsSupportedPasswordTypeForModalWarning( 245 ReusedPasswordAccountType password_type) const; 246 247 const ReusedPasswordAccountType& reused_password_account_type_for_last_shown_warning()248 reused_password_account_type_for_last_shown_warning() const { 249 return reused_password_account_type_for_last_shown_warning_; 250 } 251 #if defined(UNIT_TEST) set_reused_password_account_type_for_last_shown_warning(ReusedPasswordAccountType reused_password_account_type_for_last_shown_warning)252 void set_reused_password_account_type_for_last_shown_warning( 253 ReusedPasswordAccountType 254 reused_password_account_type_for_last_shown_warning) { 255 reused_password_account_type_for_last_shown_warning_ = 256 reused_password_account_type_for_last_shown_warning; 257 } 258 #endif 259 username_for_last_shown_warning()260 const std::string& username_for_last_shown_warning() const { 261 return username_for_last_shown_warning_; 262 } 263 #if defined(UNIT_TEST) set_username_for_last_shown_warning(const std::string & username)264 void set_username_for_last_shown_warning(const std::string& username) { 265 username_for_last_shown_warning_ = username; 266 } 267 #endif 268 saved_passwords_matching_domains()269 const std::vector<std::string>& saved_passwords_matching_domains() const { 270 return saved_passwords_matching_domains_; 271 } 272 #if defined(UNIT_TEST) set_saved_passwords_matching_domains(const std::vector<std::string> & matching_domains)273 void set_saved_passwords_matching_domains( 274 const std::vector<std::string>& matching_domains) { 275 saved_passwords_matching_domains_ = matching_domains; 276 } 277 #endif 278 279 virtual AccountInfo GetAccountInfo() const = 0; 280 281 protected: 282 friend class PasswordProtectionRequest; 283 284 // Chrome can send password protection ping if it is allowed by for the 285 // |trigger_type| and if Safe Browsing can compute reputation of 286 // |main_frame_url| (e.g. Safe Browsing is not able to compute reputation of a 287 // private IP or a local host). Update |reason| if sending ping is not 288 // allowed. |password_type| is used for UMA metric recording. 289 bool CanSendPing(LoginReputationClientRequest::TriggerType trigger_type, 290 const GURL& main_frame_url, 291 ReusedPasswordAccountType password_type, 292 RequestOutcome* reason); 293 294 // Called by a PasswordProtectionRequest instance when it finishes to remove 295 // itself from |requests_|. 296 virtual void RequestFinished( 297 PasswordProtectionRequest* request, 298 RequestOutcome outcome, 299 std::unique_ptr<LoginReputationClientResponse> response); 300 301 // Called by a PasswordProtectionRequest instance to check if a sample ping 302 // can be sent to Safe Browsing. 303 virtual bool CanSendSamplePing() = 0; 304 305 // Sanitize referrer chain by only keeping origin information of all URLs. 306 virtual void SanitizeReferrerChain(ReferrerChain* referrer_chain) = 0; 307 308 // Cancels all requests in |requests_|, empties it, and releases references to 309 // the requests. 310 void CancelPendingRequests(); 311 312 // Gets the total number of verdicts of the specified |trigger_type| we cached 313 // for this profile. This counts both expired and active verdicts. 314 virtual int GetStoredVerdictCount( 315 LoginReputationClientRequest::TriggerType trigger_type); 316 317 // Gets an unowned |BrowserPolicyConnector| for the current platform. 318 virtual const policy::BrowserPolicyConnector* GetBrowserPolicyConnector() 319 const = 0; 320 url_loader_factory()321 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory() { 322 return url_loader_factory_; 323 } 324 325 // Returns the URL where PasswordProtectionRequest instances send requests. 326 static GURL GetPasswordProtectionRequestUrl(); 327 328 // Gets the request timeout in milliseconds. 329 static int GetRequestTimeoutInMS(); 330 331 // Obtains referrer chain of |event_url| and |event_tab_id| and adds this 332 // info into |frame|. 333 virtual void FillReferrerChain( 334 const GURL& event_url, 335 SessionID 336 event_tab_id, // SessionID::InvalidValue() if tab not available. 337 LoginReputationClientRequest::Frame* frame) = 0; 338 339 void FillUserPopulation( 340 LoginReputationClientRequest::TriggerType trigger_type, 341 LoginReputationClientRequest* request_proto); 342 343 virtual bool IsExtendedReporting() = 0; 344 345 virtual bool IsEnhancedProtection() = 0; 346 347 virtual bool IsIncognito() = 0; 348 349 virtual bool IsPingingEnabled( 350 LoginReputationClientRequest::TriggerType trigger_type, 351 ReusedPasswordAccountType password_type, 352 RequestOutcome* reason) = 0; 353 354 virtual bool IsHistorySyncEnabled() = 0; 355 356 // If primary account is syncing. 357 virtual bool IsPrimaryAccountSyncing() const = 0; 358 359 // If primary account is signed in. 360 virtual bool IsPrimaryAccountSignedIn() const = 0; 361 362 // If a domain is not defined for the primary account. This means the primary 363 // account is a Gmail account. 364 virtual bool IsPrimaryAccountGmail() const = 0; 365 366 // If the domain for the non sync account is equal to |kNoHostedDomainFound|, 367 // this means that the account is a Gmail account. 368 virtual bool IsOtherGaiaAccountGmail(const std::string& username) const = 0; 369 370 // Gets the account based off of the username from a list of signed in 371 // accounts. 372 virtual AccountInfo GetSignedInNonSyncAccount( 373 const std::string& username) const = 0; 374 375 #if BUILDFLAG(FULL_SAFE_BROWSING) 376 virtual bool IsUnderAdvancedProtection() = 0; 377 #endif 378 379 #if defined(SYNC_PASSWORD_REUSE_WARNING_ENABLED) 380 // Records a Chrome Sync event for the result of the URL reputation lookup 381 // if the user enters their sync password on a website. 382 virtual void MaybeLogPasswordReuseLookupEvent( 383 content::WebContents* web_contents, 384 RequestOutcome, 385 PasswordType password_type, 386 const LoginReputationClientResponse*) = 0; 387 388 void RemoveWarningRequestsByWebContents(content::WebContents* web_contents); 389 390 bool IsModalWarningShowingInWebContents(content::WebContents* web_contents); 391 392 // Determines if we should show chrome://reset-password interstitial based on 393 // previous request outcome, the reused |password_type| and the 394 // |main_frame_url|. 395 virtual bool CanShowInterstitial(RequestOutcome reason, 396 ReusedPasswordAccountType password_type, 397 const GURL& main_frame_url) = 0; 398 #endif 399 400 void CheckCsdWhitelistOnIOThread(const GURL& url, bool* check_result); 401 402 // Gets the type of sync account associated with current profile or 403 // |NOT_SIGNED_IN|. 404 virtual LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType 405 GetSyncAccountType() const = 0; 406 common_spoofed_domains()407 const std::list<std::string>& common_spoofed_domains() const { 408 return common_spoofed_domains_; 409 } 410 411 private: 412 friend class PasswordProtectionServiceTest; 413 friend class TestPasswordProtectionService; 414 friend class ChromePasswordProtectionServiceTest; 415 friend class ChromePasswordProtectionServiceBrowserTest; 416 FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest, 417 TestParseInvalidVerdictEntry); 418 FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest, 419 TestParseValidVerdictEntry); 420 FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest, 421 TestPathVariantsMatchCacheExpression); 422 FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest, 423 TestRemoveCachedVerdictOnURLsDeleted); 424 FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest, 425 TestCleanUpExpiredVerdict); 426 427 // Overridden from history::HistoryServiceObserver. 428 void OnURLsDeleted(history::HistoryService* history_service, 429 const history::DeletionInfo& deletion_info) override; 430 431 void HistoryServiceBeingDeleted( 432 history::HistoryService* history_service) override; 433 434 // Posted to UI thread by OnURLsDeleted(...). This function remove the related 435 // entries in kSafeBrowsingUnhandledSyncPasswordReuses. 436 virtual void RemoveUnhandledSyncPasswordReuseOnURLsDeleted( 437 bool all_history, 438 const history::URLRows& deleted_rows) = 0; 439 440 static bool PathVariantsMatchCacheExpression( 441 const std::vector<std::string>& generated_paths, 442 const std::string& cache_expression_path); 443 444 void RecordNoPingingReason( 445 LoginReputationClientRequest::TriggerType trigger_type, 446 RequestOutcome reason, 447 PasswordType password_type); 448 449 #if BUILDFLAG(FULL_SAFE_BROWSING) 450 // Get the content area size of current browsing window. 451 virtual gfx::Size GetCurrentContentAreaSize() const = 0; 452 453 // Binds the |phishing_detector| to the appropriate interface, as provided by 454 // |provider|. 455 virtual void GetPhishingDetector( 456 service_manager::InterfaceProvider* provider, 457 mojo::Remote<mojom::PhishingDetector>* phishing_detector); 458 #endif 459 460 // The username of the account which password has been reused on. It is only 461 // set once a modal warning or interstitial is verified to be shown. 462 std::string username_for_last_shown_warning_ = ""; 463 464 // The last ReusedPasswordAccountType that was shown a warning or 465 // interstitial. 466 ReusedPasswordAccountType 467 reused_password_account_type_for_last_shown_warning_; 468 469 std::vector<std::string> saved_passwords_matching_domains_; 470 471 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; 472 473 // The context we use to issue network requests. This request_context_getter 474 // is obtained from SafeBrowsingService so that we can use the Safe Browsing 475 // cookie store. 476 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; 477 478 // Set of pending PasswordProtectionRequests that are still waiting for 479 // verdict. 480 std::set<scoped_refptr<PasswordProtectionRequest>> pending_requests_; 481 482 // Set of PasswordProtectionRequests that are triggering modal warnings. 483 std::set<scoped_refptr<PasswordProtectionRequest>> warning_requests_; 484 485 // List of most commonly spoofed domains to default to on the password warning 486 // dialog. 487 std::list<std::string> common_spoofed_domains_; 488 489 ScopedObserver<history::HistoryService, history::HistoryServiceObserver> 490 history_service_observer_{this}; 491 492 // Weakptr can only cancel task if it is posted to the same thread. Therefore, 493 // we need CancelableTaskTracker to cancel tasks posted to IO thread. 494 base::CancelableTaskTracker tracker_; 495 496 base::WeakPtrFactory<PasswordProtectionService> weak_factory_{this}; 497 DISALLOW_COPY_AND_ASSIGN(PasswordProtectionService); 498 }; 499 500 } // namespace safe_browsing 501 502 #endif // COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_PASSWORD_PROTECTION_SERVICE_H_ 503