OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 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 #include "components/safe_browsing/password_protection/password_protection_servi
ce.h" | 5 #include "components/safe_browsing/password_protection/password_protection_servi
ce.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
10 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "base/strings/string_split.h" | 13 #include "base/strings/string_split.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "components/content_settings/core/browser/host_content_settings_map.h" | 15 #include "components/content_settings/core/browser/host_content_settings_map.h" |
16 #include "components/history/core/browser/history_service.h" | 16 #include "components/history/core/browser/history_service.h" |
17 #include "components/safe_browsing/password_protection/password_protection_reque
st.h" | 17 #include "components/safe_browsing/password_protection/password_protection_reque
st.h" |
18 #include "components/safe_browsing_db/database_manager.h" | 18 #include "components/safe_browsing_db/database_manager.h" |
19 #include "components/safe_browsing_db/v4_protocol_manager_util.h" | 19 #include "components/safe_browsing_db/v4_protocol_manager_util.h" |
20 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
| 21 #include "content/public/browser/web_contents.h" |
21 #include "google_apis/google_api_keys.h" | 22 #include "google_apis/google_api_keys.h" |
22 #include "net/base/escape.h" | 23 #include "net/base/escape.h" |
| 24 #include "net/base/url_util.h" |
23 | 25 |
24 using content::BrowserThread; | 26 using content::BrowserThread; |
| 27 using content::WebContents; |
25 using history::HistoryService; | 28 using history::HistoryService; |
26 | 29 |
27 namespace safe_browsing { | 30 namespace safe_browsing { |
28 | 31 |
29 namespace { | 32 namespace { |
30 | 33 |
31 // Keys for storing password protection verdict into a DictionaryValue. | 34 // Keys for storing password protection verdict into a DictionaryValue. |
32 const char kCacheCreationTime[] = "cache_creation_time"; | 35 const char kCacheCreationTime[] = "cache_creation_time"; |
33 const char kVerdictProto[] = "verdict_proto"; | 36 const char kVerdictProto[] = "verdict_proto"; |
34 const int kRequestTimeoutMs = 10000; | 37 const int kRequestTimeoutMs = 10000; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 } | 102 } |
100 | 103 |
101 void PasswordProtectionService::CheckCsdWhitelistOnIOThread( | 104 void PasswordProtectionService::CheckCsdWhitelistOnIOThread( |
102 const GURL& url, | 105 const GURL& url, |
103 bool* check_result) { | 106 bool* check_result) { |
104 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 107 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
105 *check_result = | 108 *check_result = |
106 url.is_valid() ? database_manager_->MatchCsdWhitelistUrl(url) : true; | 109 url.is_valid() ? database_manager_->MatchCsdWhitelistUrl(url) : true; |
107 } | 110 } |
108 | 111 |
| 112 bool PasswordProtectionService::CanGetReputationOfURL(const GURL& url) { |
| 113 if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS()) |
| 114 return false; |
| 115 |
| 116 const std::string& hostname = url.HostNoBrackets(); |
| 117 return !net::IsLocalhost(hostname) && !net::IsHostnameNonUnique(hostname) && |
| 118 hostname.find('.') != std::string::npos; |
| 119 } |
| 120 |
109 LoginReputationClientResponse::VerdictType | 121 LoginReputationClientResponse::VerdictType |
110 PasswordProtectionService::GetCachedVerdict( | 122 PasswordProtectionService::GetCachedVerdict( |
111 const GURL& url, | 123 const GURL& url, |
112 LoginReputationClientResponse* out_response) { | 124 LoginReputationClientResponse* out_response) { |
113 if (!url.is_valid()) | 125 if (!url.is_valid()) |
114 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; | 126 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; |
115 | 127 |
116 DCHECK(content_settings_); | 128 DCHECK(content_settings_); |
117 | 129 |
118 GURL hostname = GetHostNameWithHTTPScheme(url); | 130 GURL hostname = GetHostNameWithHTTPScheme(url); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 // |verdict_diectionary|. | 256 // |verdict_diectionary|. |
245 content_settings_->SetWebsiteSettingDefaultScope( | 257 content_settings_->SetWebsiteSettingDefaultScope( |
246 primary_pattern_url, GURL(), | 258 primary_pattern_url, GURL(), |
247 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | 259 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), |
248 std::move(verdict_dictionary)); | 260 std::move(verdict_dictionary)); |
249 } | 261 } |
250 } | 262 } |
251 } | 263 } |
252 | 264 |
253 void PasswordProtectionService::StartRequest( | 265 void PasswordProtectionService::StartRequest( |
| 266 WebContents* web_contents, |
254 const GURL& main_frame_url, | 267 const GURL& main_frame_url, |
255 const GURL& password_form_action, | 268 const GURL& password_form_action, |
256 const GURL& password_form_frame_url, | 269 const GURL& password_form_frame_url, |
257 const std::string& saved_domain, | 270 const std::string& saved_domain, |
258 LoginReputationClientRequest::TriggerType type) { | 271 LoginReputationClientRequest::TriggerType type) { |
259 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 272 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
260 scoped_refptr<PasswordProtectionRequest> request( | 273 scoped_refptr<PasswordProtectionRequest> request( |
261 new PasswordProtectionRequest(main_frame_url, password_form_action, | 274 new PasswordProtectionRequest(web_contents, main_frame_url, |
| 275 password_form_action, |
262 password_form_frame_url, saved_domain, type, | 276 password_form_frame_url, saved_domain, type, |
263 this, GetRequestTimeoutInMS())); | 277 this, GetRequestTimeoutInMS())); |
264 DCHECK(request); | 278 DCHECK(request); |
265 request->Start(); | 279 request->Start(); |
266 requests_.insert(std::move(request)); | 280 requests_.insert(std::move(request)); |
267 } | 281 } |
268 | 282 |
269 void PasswordProtectionService::MaybeStartPasswordFieldOnFocusRequest( | 283 void PasswordProtectionService::MaybeStartPasswordFieldOnFocusRequest( |
| 284 WebContents* web_contents, |
270 const GURL& main_frame_url, | 285 const GURL& main_frame_url, |
271 const GURL& password_form_action, | 286 const GURL& password_form_action, |
272 const GURL& password_form_frame_url) { | 287 const GURL& password_form_frame_url) { |
273 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 288 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
274 RequestOutcome request_outcome; | 289 if (CanSendPing(kPasswordFieldOnFocusPinging, main_frame_url)) { |
275 if (!IsPingingEnabled(kPasswordFieldOnFocusPinging, &request_outcome)) { | 290 StartRequest(web_contents, main_frame_url, password_form_action, |
276 RecordPingingDisabledReason(kPasswordFieldOnFocusPinging, request_outcome); | 291 password_form_frame_url, |
277 return; | 292 std::string(), /* saved_domain: not used for this type */ |
| 293 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE); |
278 } | 294 } |
279 | |
280 // Skip URLs that we can't get a reliable reputation for. | |
281 if (!main_frame_url.is_valid() || !main_frame_url.SchemeIsHTTPOrHTTPS()) { | |
282 return; | |
283 } | |
284 | |
285 StartRequest(main_frame_url, password_form_action, password_form_frame_url, | |
286 std::string(), /* saved_domain: not used for this type */ | |
287 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE); | |
288 } | 295 } |
289 | 296 |
290 void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest( | 297 void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest( |
| 298 WebContents* web_contents, |
291 const GURL& main_frame_url, | 299 const GURL& main_frame_url, |
292 const std::string& saved_domain) { | 300 const std::string& saved_domain) { |
293 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 301 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
294 RequestOutcome request_outcome; | 302 if (CanSendPing(kProtectedPasswordEntryPinging, main_frame_url)) { |
295 if (!IsPingingEnabled(kProtectedPasswordEntryPinging, &request_outcome)) { | 303 StartRequest(web_contents, main_frame_url, GURL(), GURL(), saved_domain, |
296 RecordPingingDisabledReason(kProtectedPasswordEntryPinging, | 304 LoginReputationClientRequest::PASSWORD_REUSE_EVENT); |
297 request_outcome); | |
298 return; | |
299 } | 305 } |
| 306 } |
300 | 307 |
301 // Skip URLs that we can't get a reliable reputation for. | 308 bool PasswordProtectionService::CanSendPing(const base::Feature& feature, |
302 if (!main_frame_url.is_valid() || !main_frame_url.SchemeIsHTTPOrHTTPS()) { | 309 const GURL& main_frame_url) { |
303 return; | 310 RequestOutcome request_outcome = URL_NOT_VALID_FOR_REPUTATION_COMPUTING; |
| 311 if (IsPingingEnabled(kPasswordFieldOnFocusPinging, &request_outcome) && |
| 312 CanGetReputationOfURL(main_frame_url)) { |
| 313 return true; |
304 } | 314 } |
305 | 315 RecordNoPingingReason(feature, request_outcome); |
306 StartRequest(main_frame_url, GURL(), GURL(), saved_domain, | 316 return false; |
307 LoginReputationClientRequest::PASSWORD_REUSE_EVENT); | |
308 } | 317 } |
309 | 318 |
310 void PasswordProtectionService::RequestFinished( | 319 void PasswordProtectionService::RequestFinished( |
311 PasswordProtectionRequest* request, | 320 PasswordProtectionRequest* request, |
312 std::unique_ptr<LoginReputationClientResponse> response) { | 321 std::unique_ptr<LoginReputationClientResponse> response) { |
313 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 322 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
314 | 323 |
315 DCHECK(request); | 324 DCHECK(request); |
316 // TODO(jialiul): We don't cache verdict for incognito mode for now. | 325 if (response) |
317 // Later we may consider temporarily caching verdict. | |
318 if (response && !IsIncognito()) | |
319 CacheVerdict(request->main_frame_url(), response.get(), base::Time::Now()); | 326 CacheVerdict(request->main_frame_url(), response.get(), base::Time::Now()); |
320 | 327 |
321 // Finished processing this request. Remove it from pending list. | 328 // Finished processing this request. Remove it from pending list. |
322 for (auto it = requests_.begin(); it != requests_.end(); it++) { | 329 for (auto it = requests_.begin(); it != requests_.end(); it++) { |
323 if (it->get() == request) { | 330 if (it->get() == request) { |
324 requests_.erase(it); | 331 requests_.erase(it); |
325 break; | 332 break; |
326 } | 333 } |
327 } | 334 } |
328 } | 335 } |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 const std::string serialized_proto(verdict->SerializeAsString()); | 554 const std::string serialized_proto(verdict->SerializeAsString()); |
548 const std::vector<char> verdict_blob(serialized_proto.begin(), | 555 const std::vector<char> verdict_blob(serialized_proto.begin(), |
549 serialized_proto.end()); | 556 serialized_proto.end()); |
550 std::unique_ptr<base::Value> binary_value = | 557 std::unique_ptr<base::Value> binary_value = |
551 base::MakeUnique<base::Value>(verdict_blob); | 558 base::MakeUnique<base::Value>(verdict_blob); |
552 DCHECK_EQ(base::Value::Type::BINARY, binary_value->type()); | 559 DCHECK_EQ(base::Value::Type::BINARY, binary_value->type()); |
553 result->Set(kVerdictProto, std::move(binary_value)); | 560 result->Set(kVerdictProto, std::move(binary_value)); |
554 return result; | 561 return result; |
555 } | 562 } |
556 | 563 |
557 void PasswordProtectionService::RecordPingingDisabledReason( | 564 void PasswordProtectionService::RecordNoPingingReason( |
558 const base::Feature& feature, | 565 const base::Feature& feature, |
559 RequestOutcome reason) { | 566 RequestOutcome reason) { |
560 DCHECK(feature.name == kProtectedPasswordEntryPinging.name || | 567 DCHECK(feature.name == kProtectedPasswordEntryPinging.name || |
561 feature.name == kPasswordFieldOnFocusPinging.name); | 568 feature.name == kPasswordFieldOnFocusPinging.name); |
562 | 569 |
563 bool is_password_entry_ping = | 570 bool is_password_entry_ping = |
564 feature.name == kProtectedPasswordEntryPinging.name; | 571 feature.name == kProtectedPasswordEntryPinging.name; |
565 | 572 |
566 if (is_password_entry_ping) { | 573 if (is_password_entry_ping) { |
567 UMA_HISTOGRAM_ENUMERATION(kPasswordEntryRequestOutcomeHistogramName, reason, | 574 UMA_HISTOGRAM_ENUMERATION(kPasswordEntryRequestOutcomeHistogramName, reason, |
568 MAX_OUTCOME); | 575 MAX_OUTCOME); |
569 } else { | 576 } else { |
570 UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName, | 577 UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName, |
571 reason, MAX_OUTCOME); | 578 reason, MAX_OUTCOME); |
572 } | 579 } |
573 } | 580 } |
574 | 581 |
575 } // namespace safe_browsing | 582 } // namespace safe_browsing |
OLD | NEW |