OLD | NEW |
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/histogram.h" | 10 #include "base/metrics/histogram_macros.h" |
11 #include "base/strings/string_split.h" | 11 #include "base/strings/string_split.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "base/time/time.h" | 13 #include "base/time/time.h" |
14 #include "chrome/browser/browser_process.h" | |
15 #include "chrome/browser/chrome_notification_types.h" | |
16 #include "chrome/browser/profiles/profile.h" | |
17 #include "components/ssl_errors/error_info.h" | 14 #include "components/ssl_errors/error_info.h" |
18 #include "content/public/browser/notification_service.h" | |
19 #include "content/public/browser/web_contents.h" | |
20 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
21 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
22 #include "net/cert/x509_cert_types.h" | 17 #include "net/cert/x509_cert_types.h" |
23 #include "net/cert/x509_certificate.h" | 18 #include "net/cert/x509_certificate.h" |
24 #include "url/gurl.h" | 19 #include "url/gurl.h" |
25 | 20 |
26 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
27 #include "chrome/browser/captive_portal/captive_portal_service.h" | |
28 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" | |
29 #endif | |
30 | |
31 #if defined(OS_WIN) | 21 #if defined(OS_WIN) |
32 #include "base/win/win_util.h" | 22 #include "base/win/win_util.h" |
33 #include "base/win/windows_version.h" | 23 #include "base/win/windows_version.h" |
34 #endif | 24 #endif |
35 | 25 |
36 using base::Time; | 26 using base::Time; |
37 using base::TimeTicks; | 27 using base::TimeTicks; |
38 using base::TimeDelta; | 28 using base::TimeDelta; |
39 | 29 |
40 namespace { | 30 namespace { |
41 | 31 |
42 // Events for UMA. Do not reorder or change! | 32 // Events for UMA. Do not reorder or change! |
43 enum SSLInterstitialCause { | 33 enum SSLInterstitialCause { |
44 CLOCK_PAST, | 34 CLOCK_PAST, |
45 CLOCK_FUTURE, | 35 CLOCK_FUTURE, |
46 WWW_SUBDOMAIN_MATCH, | 36 WWW_SUBDOMAIN_MATCH, |
47 SUBDOMAIN_MATCH, | 37 SUBDOMAIN_MATCH, |
48 SUBDOMAIN_INVERSE_MATCH, | 38 SUBDOMAIN_INVERSE_MATCH, |
49 SUBDOMAIN_OUTSIDE_WILDCARD, | 39 SUBDOMAIN_OUTSIDE_WILDCARD, |
50 HOST_NAME_NOT_KNOWN_TLD, | 40 HOST_NAME_NOT_KNOWN_TLD, |
51 LIKELY_MULTI_TENANT_HOSTING, | 41 LIKELY_MULTI_TENANT_HOSTING, |
52 LOCALHOST, | 42 LOCALHOST, |
53 PRIVATE_URL, | 43 PRIVATE_URL, |
54 AUTHORITY_ERROR_CAPTIVE_PORTAL, | 44 AUTHORITY_ERROR_CAPTIVE_PORTAL, // Deprecated in M47. |
55 SELF_SIGNED, | 45 SELF_SIGNED, |
56 EXPIRED_RECENTLY, | 46 EXPIRED_RECENTLY, |
57 LIKELY_SAME_DOMAIN, | 47 LIKELY_SAME_DOMAIN, |
58 UNUSED_INTERSTITIAL_CAUSE_ENTRY, | 48 UNUSED_INTERSTITIAL_CAUSE_ENTRY, |
59 }; | 49 }; |
60 | 50 |
61 // Events for UMA. Do not reorder or change! | |
62 enum SSLInterstitialCauseCaptivePortal { | |
63 CAPTIVE_PORTAL_ALL, | |
64 CAPTIVE_PORTAL_DETECTION_ENABLED, | |
65 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE, | |
66 CAPTIVE_PORTAL_PROBE_COMPLETED, | |
67 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE, | |
68 CAPTIVE_PORTAL_NO_RESPONSE, | |
69 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE, | |
70 CAPTIVE_PORTAL_DETECTED, | |
71 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE, | |
72 UNUSED_CAPTIVE_PORTAL_EVENT, | |
73 }; | |
74 | |
75 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { | 51 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { |
76 if (overridable) { | 52 if (overridable) { |
77 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, | 53 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, |
78 UNUSED_INTERSTITIAL_CAUSE_ENTRY); | 54 UNUSED_INTERSTITIAL_CAUSE_ENTRY); |
79 } else { | 55 } else { |
80 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, | 56 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, |
81 UNUSED_INTERSTITIAL_CAUSE_ENTRY); | 57 UNUSED_INTERSTITIAL_CAUSE_ENTRY); |
82 } | 58 } |
83 } | 59 } |
84 | 60 |
85 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
86 void RecordCaptivePortalEventStats(SSLInterstitialCauseCaptivePortal event) { | |
87 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.captive_portal", | |
88 event, | |
89 UNUSED_CAPTIVE_PORTAL_EVENT); | |
90 } | |
91 #endif | |
92 | |
93 int GetLevensteinDistance(const std::string& str1, | 61 int GetLevensteinDistance(const std::string& str1, |
94 const std::string& str2) { | 62 const std::string& str2) { |
95 if (str1 == str2) | 63 if (str1 == str2) |
96 return 0; | 64 return 0; |
97 if (str1.size() == 0) | 65 if (str1.size() == 0) |
98 return str2.size(); | 66 return str2.size(); |
99 if (str2.size() == 0) | 67 if (str2.size() == 0) |
100 return str1.size(); | 68 return str1.size(); |
101 std::vector<int> kFirstRow(str2.size() + 1, 0); | 69 std::vector<int> kFirstRow(str2.size() + 1, 0); |
102 std::vector<int> kSecondRow(str2.size() + 1, 0); | 70 std::vector<int> kSecondRow(str2.size() + 1, 0); |
(...skipping 11 matching lines...) Expand all Loading... |
114 kFirstRow[j] = kSecondRow[j]; | 82 kFirstRow[j] = kSecondRow[j]; |
115 } | 83 } |
116 return kSecondRow[str2.size()]; | 84 return kSecondRow[str2.size()]; |
117 } | 85 } |
118 | 86 |
119 // The time to use when doing build time operations in browser tests. | 87 // The time to use when doing build time operations in browser tests. |
120 base::Time g_testing_build_time; | 88 base::Time g_testing_build_time; |
121 | 89 |
122 } // namespace | 90 } // namespace |
123 | 91 |
124 SSLErrorClassification::SSLErrorClassification( | 92 SSLErrorClassification::SSLErrorClassification(const base::Time& current_time, |
125 content::WebContents* web_contents, | 93 const GURL& url, |
126 const base::Time& current_time, | 94 int cert_error, |
127 const GURL& url, | 95 const net::X509Certificate& cert) |
128 int cert_error, | 96 : current_time_(current_time), |
129 const net::X509Certificate& cert) | 97 request_url_(url), |
130 : web_contents_(web_contents), | 98 cert_error_(cert_error), |
131 current_time_(current_time), | 99 cert_(cert) {} |
132 request_url_(url), | |
133 cert_error_(cert_error), | |
134 cert_(cert), | |
135 captive_portal_detection_enabled_(false), | |
136 captive_portal_probe_completed_(false), | |
137 captive_portal_no_response_(false), | |
138 captive_portal_detected_(false) { | |
139 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
140 Profile* profile = Profile::FromBrowserContext( | |
141 web_contents_->GetBrowserContext()); | |
142 captive_portal_detection_enabled_ = | |
143 CaptivePortalServiceFactory::GetForProfile(profile)->enabled(); | |
144 registrar_.Add(this, | |
145 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, | |
146 content::Source<Profile>(profile)); | |
147 #endif | |
148 } | |
149 | 100 |
150 SSLErrorClassification::~SSLErrorClassification() { } | 101 SSLErrorClassification::~SSLErrorClassification() { } |
151 | 102 |
152 void SSLErrorClassification::RecordCaptivePortalUMAStatistics( | |
153 bool overridable) const { | |
154 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
155 RecordCaptivePortalEventStats(CAPTIVE_PORTAL_ALL); | |
156 if (captive_portal_detection_enabled_) | |
157 RecordCaptivePortalEventStats( | |
158 overridable ? | |
159 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE : | |
160 CAPTIVE_PORTAL_DETECTION_ENABLED); | |
161 if (captive_portal_probe_completed_) | |
162 RecordCaptivePortalEventStats( | |
163 overridable ? | |
164 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE : | |
165 CAPTIVE_PORTAL_PROBE_COMPLETED); | |
166 // Log only one of portal detected and no response results. | |
167 if (captive_portal_detected_) | |
168 RecordCaptivePortalEventStats( | |
169 overridable ? | |
170 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE : | |
171 CAPTIVE_PORTAL_DETECTED); | |
172 else if (captive_portal_no_response_) | |
173 RecordCaptivePortalEventStats( | |
174 overridable ? | |
175 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE : | |
176 CAPTIVE_PORTAL_NO_RESPONSE); | |
177 #endif | |
178 } | |
179 | |
180 void SSLErrorClassification::RecordUMAStatistics( | 103 void SSLErrorClassification::RecordUMAStatistics( |
181 bool overridable) const { | 104 bool overridable) const { |
182 ssl_errors::ErrorInfo::ErrorType type = | 105 ssl_errors::ErrorInfo::ErrorType type = |
183 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_); | 106 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_); |
184 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type, | 107 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type, |
185 ssl_errors::ErrorInfo::END_OF_ENUM); | 108 ssl_errors::ErrorInfo::END_OF_ENUM); |
186 switch (type) { | 109 switch (type) { |
187 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: { | 110 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: { |
188 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) { | 111 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) { |
189 RecordSSLInterstitialCause(overridable, CLOCK_PAST); | 112 RecordSSLInterstitialCause(overridable, CLOCK_PAST); |
(...skipping 28 matching lines...) Expand all Loading... |
218 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); | 141 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); |
219 } | 142 } |
220 break; | 143 break; |
221 } | 144 } |
222 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: { | 145 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: { |
223 const std::string& hostname = request_url_.HostNoBrackets(); | 146 const std::string& hostname = request_url_.HostNoBrackets(); |
224 if (net::IsLocalhost(hostname)) | 147 if (net::IsLocalhost(hostname)) |
225 RecordSSLInterstitialCause(overridable, LOCALHOST); | 148 RecordSSLInterstitialCause(overridable, LOCALHOST); |
226 if (IsHostnameNonUniqueOrDotless(hostname)) | 149 if (IsHostnameNonUniqueOrDotless(hostname)) |
227 RecordSSLInterstitialCause(overridable, PRIVATE_URL); | 150 RecordSSLInterstitialCause(overridable, PRIVATE_URL); |
228 if (captive_portal_probe_completed_ && captive_portal_detected_) | |
229 RecordSSLInterstitialCause(overridable, AUTHORITY_ERROR_CAPTIVE_PORTAL); | |
230 if (net::X509Certificate::IsSelfSigned(cert_.os_cert_handle())) | 151 if (net::X509Certificate::IsSelfSigned(cert_.os_cert_handle())) |
231 RecordSSLInterstitialCause(overridable, SELF_SIGNED); | 152 RecordSSLInterstitialCause(overridable, SELF_SIGNED); |
232 break; | 153 break; |
233 } | 154 } |
234 default: | 155 default: |
235 break; | 156 break; |
236 } | 157 } |
237 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type", | 158 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type", |
238 net::NetworkChangeNotifier::GetConnectionType(), | 159 net::NetworkChangeNotifier::GetConnectionType(), |
239 net::NetworkChangeNotifier::CONNECTION_LAST); | 160 net::NetworkChangeNotifier::CONNECTION_LAST); |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
514 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, | 435 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, |
515 host_name_domain) != dns_names_domain.end() - 1; | 436 host_name_domain) != dns_names_domain.end() - 1; |
516 } | 437 } |
517 | 438 |
518 // static | 439 // static |
519 bool SSLErrorClassification::IsHostnameNonUniqueOrDotless( | 440 bool SSLErrorClassification::IsHostnameNonUniqueOrDotless( |
520 const std::string& hostname) { | 441 const std::string& hostname) { |
521 return net::IsHostnameNonUnique(hostname) || | 442 return net::IsHostnameNonUnique(hostname) || |
522 hostname.find('.') == std::string::npos; | 443 hostname.find('.') == std::string::npos; |
523 } | 444 } |
524 | |
525 void SSLErrorClassification::Observe( | |
526 int type, | |
527 const content::NotificationSource& source, | |
528 const content::NotificationDetails& details) { | |
529 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
530 // When detection is disabled, captive portal service always sends | |
531 // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case. | |
532 if (!captive_portal_detection_enabled_) | |
533 return; | |
534 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { | |
535 captive_portal_probe_completed_ = true; | |
536 CaptivePortalService::Results* results = | |
537 content::Details<CaptivePortalService::Results>(details).ptr(); | |
538 // If a captive portal was detected at any point when the interstitial was | |
539 // displayed, assume that the interstitial was caused by a captive portal. | |
540 // Example scenario: | |
541 // 1- Interstitial displayed and captive portal detected, setting the flag. | |
542 // 2- Captive portal detection automatically opens portal login page. | |
543 // 3- User logs in on the portal login page. | |
544 // A notification will be received here for RESULT_INTERNET_CONNECTED. Make | |
545 // sure we don't clear the captive protal flag, since the interstitial was | |
546 // potentially caused by the captive portal. | |
547 captive_portal_detected_ = captive_portal_detected_ || | |
548 (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL); | |
549 // Also keep track of non-HTTP portals and error cases. | |
550 captive_portal_no_response_ = captive_portal_no_response_ || | |
551 (results->result == captive_portal::RESULT_NO_RESPONSE); | |
552 } | |
553 #endif | |
554 } | |
OLD | NEW |