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

Side by Side Diff: chrome/browser/ssl/ssl_error_classification.cc

Issue 400323002: Refactor the captive portal code to move from the ssl_blocking_page class to the ssl_error_classific (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed typo Created 6 years, 4 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 <vector> 5 #include <vector>
6 6
7 #include "chrome/browser/ssl/ssl_error_classification.h" 7 #include "chrome/browser/ssl/ssl_error_classification.h"
8 8
9 #include "base/build_time.h" 9 #include "base/build_time.h"
10 #include "base/metrics/field_trial.h" 10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_split.h" 12 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ssl/ssl_error_info.h" 18 #include "chrome/browser/ssl/ssl_error_info.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/web_contents.h"
16 #include "net/base/net_util.h" 21 #include "net/base/net_util.h"
17 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
18 #include "net/cert/x509_cert_types.h" 23 #include "net/cert/x509_cert_types.h"
19 #include "net/cert/x509_certificate.h" 24 #include "net/cert/x509_certificate.h"
20 #include "url/gurl.h" 25 #include "url/gurl.h"
21 26
22 using base::Time; 27 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
23 using base::TimeTicks; 28 #include "chrome/browser/captive_portal/captive_portal_service.h"
24 using base::TimeDelta; 29 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
30 #endif
25 31
26 #if defined(OS_WIN) 32 #if defined(OS_WIN)
27 #include "base/win/windows_version.h" 33 #include "base/win/windows_version.h"
28 #endif 34 #endif
29 35
36 using base::Time;
37 using base::TimeTicks;
38 using base::TimeDelta;
39
30 namespace { 40 namespace {
31 41
32 // Events for UMA. Do not reorder or change! 42 // Events for UMA. Do not reorder or change!
33 enum SSLInterstitialCause { 43 enum SSLInterstitialCause {
34 CLOCK_PAST, 44 CLOCK_PAST,
35 CLOCK_FUTURE, 45 CLOCK_FUTURE,
36 WWW_SUBDOMAIN_MATCH, 46 WWW_SUBDOMAIN_MATCH,
37 SUBDOMAIN_MATCH, 47 SUBDOMAIN_MATCH,
38 SUBDOMAIN_INVERSE_MATCH, 48 SUBDOMAIN_INVERSE_MATCH,
39 SUBDOMAIN_OUTSIDE_WILDCARD, 49 SUBDOMAIN_OUTSIDE_WILDCARD,
40 HOST_NAME_NOT_KNOWN_TLD, 50 HOST_NAME_NOT_KNOWN_TLD,
41 UNUSED_INTERSTITIAL_CAUSE_ENTRY, 51 UNUSED_INTERSTITIAL_CAUSE_ENTRY,
42 }; 52 };
43 53
54 // Events for UMA. Do not reorder or change!
55 enum SSLInterstitialCauseCaptivePortal {
56 CAPTIVE_PORTAL_DETECTION_ENABLED,
57 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
58 CAPTIVE_PORTAL_PROBE_COMPLETED,
59 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
60 CAPTIVE_PORTAL_NO_RESPONSE,
61 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
62 CAPTIVE_PORTAL_DETECTED,
63 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
64 UNUSED_CAPTIVE_PORTAL_EVENT,
65 };
66
44 // Scores/weights which will be constant through all the SSL error types. 67 // Scores/weights which will be constant through all the SSL error types.
45 static const float kServerWeight = 0.5f; 68 static const float kServerWeight = 0.5f;
46 static const float kClientWeight = 0.5f; 69 static const float kClientWeight = 0.5f;
47 70
48 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { 71 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) {
49 if (overridable) { 72 if (overridable) {
50 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, 73 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event,
51 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 74 UNUSED_INTERSTITIAL_CAUSE_ENTRY);
52 } else { 75 } else {
53 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, 76 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event,
54 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 77 UNUSED_INTERSTITIAL_CAUSE_ENTRY);
55 } 78 }
56 } 79 }
57 80
81 void RecordCaptivePortalEventStats(SSLInterstitialCauseCaptivePortal event) {
82 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.captive_portal",
83 event,
84 UNUSED_CAPTIVE_PORTAL_EVENT);
85 }
86
58 } // namespace 87 } // namespace
59 88
60 SSLErrorClassification::SSLErrorClassification( 89 SSLErrorClassification::SSLErrorClassification(
90 content::WebContents* web_contents,
61 const base::Time& current_time, 91 const base::Time& current_time,
62 const GURL& url, 92 const GURL& url,
93 int cert_error,
63 const net::X509Certificate& cert) 94 const net::X509Certificate& cert)
64 : current_time_(current_time), 95 : web_contents_(web_contents),
96 current_time_(current_time),
65 request_url_(url), 97 request_url_(url),
66 cert_(cert) { } 98 cert_error_(cert_error),
99 cert_(cert),
100 captive_portal_detection_enabled_(false),
101 captive_portal_probe_completed_(false),
102 captive_portal_no_response_(false),
103 captive_portal_detected_(false) {
104 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
105 Profile* profile = Profile::FromBrowserContext(
106 web_contents_->GetBrowserContext());
107 CaptivePortalService* captive_portal_service =
108 CaptivePortalServiceFactory::GetForProfile(profile);
109 captive_portal_detection_enabled_ = captive_portal_service->enabled();
110 captive_portal_service->DetectCaptivePortal();
111 registrar_.Add(this,
112 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
113 content::Source<Profile>(profile));
114 #endif
115 }
67 116
68 SSLErrorClassification::~SSLErrorClassification() { } 117 SSLErrorClassification::~SSLErrorClassification() { }
69 118
70 float SSLErrorClassification::InvalidDateSeverityScore( 119 void SSLErrorClassification::RecordCaptivePortalUMAStatistics(
71 int cert_error) const { 120 bool overridable) const {
121 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
122 if (captive_portal_detection_enabled_)
123 RecordCaptivePortalEventStats(
124 overridable ?
125 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE :
126 CAPTIVE_PORTAL_DETECTION_ENABLED);
127 if (captive_portal_probe_completed_)
128 RecordCaptivePortalEventStats(
129 overridable ?
130 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE :
131 CAPTIVE_PORTAL_PROBE_COMPLETED);
132 // Log only one of portal detected and no response results.
133 if (captive_portal_detected_)
134 RecordCaptivePortalEventStats(
135 overridable ?
136 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE :
137 CAPTIVE_PORTAL_DETECTED);
138 else if (captive_portal_no_response_)
139 RecordCaptivePortalEventStats(
140 overridable ?
141 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE :
142 CAPTIVE_PORTAL_NO_RESPONSE);
143 #endif
144 }
145
146 void SSLErrorClassification::InvalidDateSeverityScore() const {
72 SSLErrorInfo::ErrorType type = 147 SSLErrorInfo::ErrorType type =
73 SSLErrorInfo::NetErrorToErrorType(cert_error); 148 SSLErrorInfo::NetErrorToErrorType(cert_error_);
74 DCHECK(type == SSLErrorInfo::CERT_DATE_INVALID); 149 DCHECK(type == SSLErrorInfo::CERT_DATE_INVALID);
150
75 // Client-side characteristics. Check whether or not the system's clock is 151 // Client-side characteristics. Check whether or not the system's clock is
76 // wrong and whether or not the user has already encountered this error 152 // wrong and whether or not the user has encountered this error before.
77 // before.
78 float severity_date_score = 0.0f; 153 float severity_date_score = 0.0f;
79 154
80 static const float kCertificateExpiredWeight = 0.3f; 155 static const float kCertificateExpiredWeight = 0.3f;
81 static const float kNotYetValidWeight = 0.2f; 156 static const float kNotYetValidWeight = 0.2f;
82 157
83 static const float kSystemClockWeight = 0.75f; 158 static const float kSystemClockWeight = 0.75f;
84 static const float kSystemClockWrongWeight = 0.1f; 159 static const float kSystemClockWrongWeight = 0.1f;
85 static const float kSystemClockRightWeight = 1.0f; 160 static const float kSystemClockRightWeight = 1.0f;
86 161
87 if (IsUserClockInThePast(current_time_) || 162 if (IsUserClockInThePast(current_time_) ||
88 IsUserClockInTheFuture(current_time_)) { 163 IsUserClockInTheFuture(current_time_)) {
89 severity_date_score += kClientWeight * kSystemClockWeight * 164 severity_date_score += kClientWeight * kSystemClockWeight *
90 kSystemClockWrongWeight; 165 kSystemClockWrongWeight;
91 } else { 166 } else {
92 severity_date_score += kClientWeight * kSystemClockWeight * 167 severity_date_score += kClientWeight * kSystemClockWeight *
93 kSystemClockRightWeight; 168 kSystemClockRightWeight;
94 } 169 }
95 // TODO(radhikabhar): (crbug.com/393262) Check website settings. 170 // TODO(radhikabhar): (crbug.com/393262) Check website settings.
96 171
97 // Server-side characteristics. Check whether the certificate has expired or 172 // Server-side characteristics. Check whether the certificate has expired or
98 // is not yet valid. If the certificate has expired then factor the time which 173 // is not yet valid. If the certificate has expired then factor the time which
99 // has passed since expiry. 174 // has passed since expiry.
100 if (cert_.HasExpired()) { 175 if (cert_.HasExpired()) {
101 severity_date_score += kServerWeight * kCertificateExpiredWeight * 176 severity_date_score += kServerWeight * kCertificateExpiredWeight *
102 CalculateScoreTimePassedSinceExpiry(); 177 CalculateScoreTimePassedSinceExpiry();
103 } 178 }
104 if (current_time_ < cert_.valid_start()) 179 if (current_time_ < cert_.valid_start())
105 severity_date_score += kServerWeight * kNotYetValidWeight; 180 severity_date_score += kServerWeight * kNotYetValidWeight;
106 return severity_date_score; 181 // TODO(radhikabhar): Record the severity score in a histogram. This will be
182 // in the next CL - just called the function in ssl_blocking_page.cc.
107 } 183 }
108 184
109 float SSLErrorClassification::InvalidCommonNameSeverityScore( 185 void SSLErrorClassification::InvalidCommonNameSeverityScore() const {
110 int cert_error) const {
111 SSLErrorInfo::ErrorType type = 186 SSLErrorInfo::ErrorType type =
112 SSLErrorInfo::NetErrorToErrorType(cert_error); 187 SSLErrorInfo::NetErrorToErrorType(cert_error_);
113 DCHECK(type == SSLErrorInfo::CERT_COMMON_NAME_INVALID); 188 DCHECK(type == SSLErrorInfo::CERT_COMMON_NAME_INVALID);
114 float severity_name_score = 0.0f; 189 float severity_name_score = 0.0f;
115 190
116 static const float kWWWDifferenceWeight = 0.3f; 191 static const float kWWWDifferenceWeight = 0.3f;
117 static const float kSubDomainWeight = 0.2f; 192 static const float kNameUnderAnyNamesWeight = 0.2f;
118 static const float kSubDomainInverseWeight = 1.0f; 193 static const float kAnyNamesUnderNamesWeight = 1.0f;
119 194
120 std::string host_name = request_url_.host(); 195 std::string host_name = request_url_.host();
121 if (IsHostNameKnownTLD(host_name)) { 196 if (IsHostNameKnownTLD(host_name)) {
122 Tokens host_name_tokens = Tokenize(host_name); 197 Tokens host_name_tokens = Tokenize(host_name);
123 if (IsWWWSubDomainMatch()) 198 if (IsWWWSubDomainMatch())
124 severity_name_score += kServerWeight * kWWWDifferenceWeight; 199 severity_name_score += kServerWeight * kWWWDifferenceWeight;
125 if (IsSubDomainOutsideWildcard(host_name_tokens)) 200 if (IsSubDomainOutsideWildcard(host_name_tokens))
126 severity_name_score += kServerWeight * kWWWDifferenceWeight; 201 severity_name_score += kServerWeight * kWWWDifferenceWeight;
127 202
128 std::vector<std::string> dns_names; 203 std::vector<std::string> dns_names;
129 cert_.GetDNSNames(&dns_names); 204 cert_.GetDNSNames(&dns_names);
130 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); 205 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names);
131 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) 206 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens))
132 severity_name_score += kServerWeight * kSubDomainWeight; 207 severity_name_score += kServerWeight * kNameUnderAnyNamesWeight;
133 // Inverse case is more likely to be a MITM attack. 208 // Inverse case is more likely to be a MITM attack.
134 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) 209 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens))
135 severity_name_score += kServerWeight * kSubDomainInverseWeight; 210 severity_name_score += kServerWeight * kAnyNamesUnderNamesWeight;
136 } 211 }
137 return severity_name_score; 212
213 static const float kEnvironmentWeight = 0.25f;
214
215 severity_name_score += kClientWeight * kEnvironmentWeight *
216 CalculateScoreEnvironments();
217 // TODO(radhikabhar): Record the severity score in a histogram. Same as above
218 // - this will be in the next CL. So just called the function in the
219 // ssl_blocking_page.cc.
138 } 220 }
139 221
140 void SSLErrorClassification::RecordUMAStatistics(bool overridable, 222 void SSLErrorClassification::RecordUMAStatistics(
141 int cert_error) { 223 bool overridable) const {
142 SSLErrorInfo::ErrorType type = 224 SSLErrorInfo::ErrorType type =
143 SSLErrorInfo::NetErrorToErrorType(cert_error); 225 SSLErrorInfo::NetErrorToErrorType(cert_error_);
144 switch (type) { 226 switch (type) {
145 case SSLErrorInfo::CERT_DATE_INVALID: { 227 case SSLErrorInfo::CERT_DATE_INVALID: {
146 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) 228 if (IsUserClockInThePast(base::Time::NowFromSystemTime()))
147 RecordSSLInterstitialCause(overridable, CLOCK_PAST); 229 RecordSSLInterstitialCause(overridable, CLOCK_PAST);
148 if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) 230 if (IsUserClockInTheFuture(base::Time::NowFromSystemTime()))
149 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); 231 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE);
150 break; 232 break;
151 } 233 }
152 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: { 234 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
153 std::string host_name = request_url_.host(); 235 std::string host_name = request_url_.host();
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 static const float kMediumThresholdWeight = 0.3f; 271 static const float kMediumThresholdWeight = 0.3f;
190 static const float kLowThresholdWeight = 0.2f; 272 static const float kLowThresholdWeight = 0.2f;
191 if (time_passed >= kHighThreshold) 273 if (time_passed >= kHighThreshold)
192 return kHighThresholdWeight; 274 return kHighThresholdWeight;
193 else if (time_passed >= kLowThreshold) 275 else if (time_passed >= kLowThreshold)
194 return kMediumThresholdWeight; 276 return kMediumThresholdWeight;
195 else 277 else
196 return kLowThresholdWeight; 278 return kLowThresholdWeight;
197 } 279 }
198 280
281 float SSLErrorClassification::CalculateScoreEnvironments() const {
282 static const float kWifiWeight = 0.7f;
283 static const float kCellularWeight = 0.7f;
284 static const float kHotspotWeight = 0.2f;
285 static const float kEthernetWeight = 0.7f;
286 static const float kOtherWeight = 0.7f;
287 net::NetworkChangeNotifier::ConnectionType type =
288 net::NetworkChangeNotifier::GetConnectionType();
289 if (type == net::NetworkChangeNotifier::CONNECTION_WIFI)
290 return kWifiWeight;
291 if (type == net::NetworkChangeNotifier::CONNECTION_2G ||
292 type == net::NetworkChangeNotifier::CONNECTION_3G ||
293 type == net::NetworkChangeNotifier::CONNECTION_4G ) {
294 return kCellularWeight;
295 }
296 if (type == net::NetworkChangeNotifier::CONNECTION_ETHERNET)
297 return kEthernetWeight;
298 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
299 // Assume if captive portals are detected then the user is connected using a
300 // hot spot.
301 if (captive_portal_probe_completed_ && captive_portal_detected_)
302 return kHotspotWeight;
303 #endif
304 return kOtherWeight;
305 }
306
199 bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { 307 bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) {
200 base::Time build_time = base::GetBuildTime(); 308 base::Time build_time = base::GetBuildTime();
201 if (time_now < build_time - base::TimeDelta::FromDays(2)) 309 if (time_now < build_time - base::TimeDelta::FromDays(2))
202 return true; 310 return true;
203 return false; 311 return false;
204 } 312 }
205 313
206 bool SSLErrorClassification::IsUserClockInTheFuture( 314 bool SSLErrorClassification::IsUserClockInTheFuture(
207 const base::Time& time_now) { 315 const base::Time& time_now) {
208 base::Time build_time = base::GetBuildTime(); 316 base::Time build_time = base::GetBuildTime();
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 467
360 // Move past the "*.". 468 // Move past the "*.".
361 std::string extracted_dns_name = name.substr(2); 469 std::string extracted_dns_name = name.substr(2);
362 if (FindSubDomainDifference( 470 if (FindSubDomainDifference(
363 host_name_tokens, Tokenize(extracted_dns_name)) == 2) { 471 host_name_tokens, Tokenize(extracted_dns_name)) == 2) {
364 return true; 472 return true;
365 } 473 }
366 } 474 }
367 return result; 475 return result;
368 } 476 }
477
478 void SSLErrorClassification::Observe(
479 int type,
480 const content::NotificationSource& source,
481 const content::NotificationDetails& details) {
482 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
483 // When detection is disabled, captive portal service always sends
484 // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case.
485 if (!captive_portal_detection_enabled_)
486 return;
487 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
488 captive_portal_probe_completed_ = true;
489 CaptivePortalService::Results* results =
490 content::Details<CaptivePortalService::Results>(
491 details).ptr();
492 // If a captive portal was detected at any point when the interstitial was
493 // displayed, assume that the interstitial was caused by a captive portal.
494 // Example scenario:
495 // 1- Interstitial displayed and captive portal detected, setting the flag.
496 // 2- Captive portal detection automatically opens portal login page.
497 // 3- User logs in on the portal login page.
498 // A notification will be received here for RESULT_INTERNET_CONNECTED. Make
499 // sure we don't clear the captive protal flag, since the interstitial was
500 // potentially caused by the captive portal.
501 captive_portal_detected_ = captive_portal_detected_ ||
502 (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
503 // Also keep track of non-HTTP portals and error cases.
504 captive_portal_no_response_ = captive_portal_no_response_ ||
505 (results->result == captive_portal::RESULT_NO_RESPONSE);
506 }
507 #endif
508 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698