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 "chrome/browser/ssl/ssl_error_classification.h" | 5 #include "chrome/browser/ssl/ssl_error_classification.h" |
6 | 6 |
7 #include "base/build_time.h" | 7 #include "base/build_time.h" |
8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
11 #include "chrome/browser/browser_process.h" | 11 #include "chrome/browser/browser_process.h" |
12 #include "components/network_time/network_time_tracker.h" | 12 #include "chrome/browser/chrome_notification_types.h" |
13 #include "chrome/browser/profiles/profile.h" | |
14 #include "chrome/browser/ssl/ssl_error_info.h" | |
15 #include "content/public/browser/notification_service.h" | |
16 #include "content/public/browser/web_contents.h" | |
17 #include "net/base/network_change_notifier.h" | |
13 #include "net/cert/x509_certificate.h" | 18 #include "net/cert/x509_certificate.h" |
14 | 19 |
20 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
21 #include "chrome/browser/captive_portal/captive_portal_service.h" | |
22 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" | |
23 #endif | |
24 | |
25 #if defined(OS_WIN) | |
26 #include "base/win/windows_version.h" | |
27 #endif | |
28 | |
15 using base::Time; | 29 using base::Time; |
16 using base::TimeTicks; | 30 using base::TimeTicks; |
17 using base::TimeDelta; | 31 using base::TimeDelta; |
18 | 32 |
19 #if defined(OS_WIN) | |
20 #include "base/win/windows_version.h" | |
21 #endif | |
22 | |
23 namespace { | 33 namespace { |
24 | 34 |
25 // Events for UMA. Do not reorder or change! | 35 // Events for UMA. Do not reorder or change! |
26 enum SSLInterstitialCause { | 36 enum SSLInterstitialCause { |
27 CLOCK_PAST, | 37 CLOCK_PAST, |
28 CLOCK_FUTURE, | 38 CLOCK_FUTURE, |
29 UNUSED_INTERSTITIAL_CAUSE_ENTRY, | 39 UNUSED_INTERSTITIAL_CAUSE_ENTRY, |
30 }; | 40 }; |
31 | 41 |
42 // Events for UMA. Do not reorder or change! | |
43 enum SSLInterstitialCauseCaptivePortal { | |
44 CAPTIVE_PORTAL_DETECTION_ENABLED, | |
45 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE, | |
46 CAPTIVE_PORTAL_PROBE_COMPLETED, | |
47 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE, | |
48 CAPTIVE_PORTAL_NO_RESPONSE, | |
49 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE, | |
50 CAPTIVE_PORTAL_DETECTED, | |
51 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE, | |
52 UNUSED_CAPTIVE_PORTAL_EVENT, | |
53 }; | |
54 | |
55 void RecordSSLInterstitialSeverityScore(float ssl_severity_score, | |
56 int cert_error) { | |
57 if (SSLErrorInfo::NetErrorToErrorType(cert_error) == | |
58 SSLErrorInfo::CERT_DATE_INVALID) { | |
59 UMA_HISTOGRAM_CUSTOM_COUNTS("interstitial.ssl.severity_score.date_invalid", | |
60 static_cast<int>(ssl_severity_score * 100), | |
61 0, 100, 20); | |
62 } | |
63 } | |
64 | |
32 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { | 65 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { |
33 if (overridable) { | 66 if (overridable) { |
34 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, | 67 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, |
35 UNUSED_INTERSTITIAL_CAUSE_ENTRY); | 68 UNUSED_INTERSTITIAL_CAUSE_ENTRY); |
36 } else { | 69 } else { |
37 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, | 70 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, |
38 UNUSED_INTERSTITIAL_CAUSE_ENTRY); | 71 UNUSED_INTERSTITIAL_CAUSE_ENTRY); |
39 } | 72 } |
40 } | 73 } |
41 | 74 |
75 void RecordCaptivePortalEventStats(SSLInterstitialCauseCaptivePortal event) { | |
76 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.captive_portal", | |
77 event, | |
78 UNUSED_CAPTIVE_PORTAL_EVENT); | |
79 } | |
80 | |
42 } // namespace | 81 } // namespace |
43 | 82 |
44 SSLErrorClassification::SSLErrorClassification( | 83 SSLErrorClassification::SSLErrorClassification( |
84 content::WebContents* web_contents, | |
45 base::Time current_time, | 85 base::Time current_time, |
86 int cert_error, | |
46 const net::X509Certificate& cert) | 87 const net::X509Certificate& cert) |
47 : current_time_(current_time), | 88 : web_contents_(web_contents), |
48 cert_(cert) { } | 89 current_time_(current_time), |
90 cert_error_(cert_error), | |
91 cert_(cert), | |
92 captive_portal_detection_enabled_(false), | |
93 captive_portal_probe_completed_(false), | |
94 captive_portal_no_response_(false), | |
95 captive_portal_detected_(false) { | |
96 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
97 Profile* profile = Profile::FromBrowserContext( | |
98 web_contents_->GetBrowserContext()); | |
99 CaptivePortalService* captive_portal_service = | |
100 CaptivePortalServiceFactory::GetForProfile(profile); | |
101 captive_portal_detection_enabled_ = captive_portal_service ->enabled(); | |
102 captive_portal_service ->DetectCaptivePortal(); | |
103 registrar_.Add(this, | |
104 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, | |
105 content::Source<Profile>(profile)); | |
106 #endif | |
107 } | |
49 | 108 |
50 SSLErrorClassification::~SSLErrorClassification() { } | 109 SSLErrorClassification::~SSLErrorClassification() { } |
51 | 110 |
52 float SSLErrorClassification::InvalidDateSeverityScore() const { | 111 void SSLErrorClassification::InvalidDateSeverityScore() const { |
53 // Client-side characterisitics. Check whether the system's clock is wrong or | 112 // Client-side characteristics. Check whether or not the system's clock is |
54 // not and whether the user has encountered this error before or not. | 113 // wrong and whether or not the user has encountered this error before. |
55 float severity_date_score = 0.0f; | 114 float severity_date_score = 0.0f; |
56 | 115 |
57 static const float kClientWeight = 0.5f; | 116 static const float kClientWeight = 0.5f; |
58 static const float kSystemClockWeight = 0.75f; | 117 static const float kSystemClockWeight = 0.75f; |
59 static const float kSystemClockWrongWeight = 0.1f; | 118 static const float kSystemClockWrongWeight = 0.1f; |
60 static const float kSystemClockRightWeight = 1.0f; | 119 static const float kSystemClockRightWeight = 1.0f; |
61 | 120 |
62 static const float kServerWeight = 0.5f; | 121 static const float kServerWeight = 0.5f; |
63 static const float kCertificateExpiredWeight = 0.3f; | 122 static const float kCertificateExpiredWeight = 0.3f; |
64 static const float kNotYetValidWeight = 0.2f; | 123 static const float kNotYetValidWeight = 0.2f; |
(...skipping 10 matching lines...) Expand all Loading... | |
75 | 134 |
76 // Server-side characteristics. Check whether the certificate has expired or | 135 // Server-side characteristics. Check whether the certificate has expired or |
77 // is not yet valid. If the certificate has expired then factor the time which | 136 // is not yet valid. If the certificate has expired then factor the time which |
78 // has passed since expiry. | 137 // has passed since expiry. |
79 if (cert_.HasExpired()) { | 138 if (cert_.HasExpired()) { |
80 severity_date_score += kServerWeight * kCertificateExpiredWeight * | 139 severity_date_score += kServerWeight * kCertificateExpiredWeight * |
81 CalculateScoreTimePassedSinceExpiry(); | 140 CalculateScoreTimePassedSinceExpiry(); |
82 } | 141 } |
83 if (current_time_ < cert_.valid_start()) | 142 if (current_time_ < cert_.valid_start()) |
84 severity_date_score += kServerWeight * kNotYetValidWeight; | 143 severity_date_score += kServerWeight * kNotYetValidWeight; |
85 return severity_date_score; | 144 RecordSSLInterstitialSeverityScore(severity_date_score, cert_error_); |
145 } | |
146 | |
147 void SSLErrorClassification::RecordUMAStatistics(bool overridable) const { | |
148 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) | |
149 RecordSSLInterstitialCause(overridable, CLOCK_PAST); | |
150 if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) | |
151 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); | |
152 } | |
153 | |
154 void SSLErrorClassification::RecordCaptivePortalUMAStatistics( | |
155 bool overridable) const { | |
156 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
157 if (captive_portal_detection_enabled_) | |
158 RecordCaptivePortalEventStats( | |
159 overridable ? | |
160 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE : | |
161 CAPTIVE_PORTAL_DETECTION_ENABLED); | |
162 if (captive_portal_probe_completed_) | |
163 RecordCaptivePortalEventStats( | |
164 overridable ? | |
165 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE : | |
166 CAPTIVE_PORTAL_PROBE_COMPLETED); | |
167 // Log only one of portal detected and no response results. | |
168 if (captive_portal_detected_) | |
169 RecordCaptivePortalEventStats( | |
170 overridable ? | |
171 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE : | |
172 CAPTIVE_PORTAL_DETECTED); | |
173 else if (captive_portal_no_response_) | |
174 RecordCaptivePortalEventStats( | |
175 overridable ? | |
176 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE : | |
177 CAPTIVE_PORTAL_NO_RESPONSE); | |
178 #endif | |
86 } | 179 } |
87 | 180 |
88 base::TimeDelta SSLErrorClassification::TimePassedSinceExpiry() const { | 181 base::TimeDelta SSLErrorClassification::TimePassedSinceExpiry() const { |
89 base::TimeDelta delta = current_time_ - cert_.valid_expiry(); | 182 base::TimeDelta delta = current_time_ - cert_.valid_expiry(); |
90 return delta; | 183 return delta; |
91 } | 184 } |
92 | 185 |
93 float SSLErrorClassification::CalculateScoreTimePassedSinceExpiry() const { | 186 float SSLErrorClassification::CalculateScoreTimePassedSinceExpiry() const { |
94 base::TimeDelta delta = TimePassedSinceExpiry(); | 187 base::TimeDelta delta = TimePassedSinceExpiry(); |
95 int64 time_passed = delta.InDays(); | 188 int64 time_passed = delta.InDays(); |
96 const int64 kHighThreshold = 7; | 189 const int64 kHighThreshold = 7; |
97 const int64 kLowThreshold = 4; | 190 const int64 kLowThreshold = 4; |
98 static const float kHighThresholdWeight = 0.4f; | 191 static const float kHighThresholdWeight = 0.4f; |
99 static const float kMediumThresholdWeight = 0.3f; | 192 static const float kMediumThresholdWeight = 0.3f; |
100 static const float kLowThresholdWeight = 0.2f; | 193 static const float kLowThresholdWeight = 0.2f; |
101 if (time_passed >= kHighThreshold) | 194 if (time_passed >= kHighThreshold) |
102 return kHighThresholdWeight; | 195 return kHighThresholdWeight; |
103 else if (time_passed >= kLowThreshold) | 196 else if (time_passed >= kLowThreshold) |
104 return kMediumThresholdWeight; | 197 return kMediumThresholdWeight; |
105 else | 198 else |
106 return kLowThresholdWeight; | 199 return kLowThresholdWeight; |
107 } | 200 } |
108 | 201 |
202 float SSLErrorClassification::CalculateScoreEnvironments() const { | |
203 static const float kWifiWeight = 0.7f; | |
204 static const float kCellularWeight = 0.7f; | |
205 static const float kHotspotWeight = 0.2f; | |
206 static const float kEthernetWeight = 0.7f; | |
207 static const float kOtherWeight = 0.7f; | |
208 net::NetworkChangeNotifier::ConnectionType type = | |
209 net::NetworkChangeNotifier::GetConnectionType(); | |
210 if (type == net::NetworkChangeNotifier::CONNECTION_WIFI) | |
211 return kWifiWeight; | |
212 if (type == net::NetworkChangeNotifier::CONNECTION_2G || | |
213 type == net::NetworkChangeNotifier::CONNECTION_3G || | |
214 type == net::NetworkChangeNotifier::CONNECTION_4G ) { | |
215 return kCellularWeight; | |
216 } | |
217 if (type == net::NetworkChangeNotifier::CONNECTION_ETHERNET) | |
218 return kEthernetWeight; | |
219 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
220 // Assume if captive portals are detected then the user is connected using a | |
221 // hot spot. | |
222 if (captive_portal_probe_completed_ && captive_portal_detected_) | |
223 return kHotspotWeight; | |
224 #endif | |
225 return kOtherWeight; | |
226 } | |
227 | |
109 bool SSLErrorClassification::IsUserClockInThePast(base::Time time_now) { | 228 bool SSLErrorClassification::IsUserClockInThePast(base::Time time_now) { |
110 base::Time build_time = base::GetBuildTime(); | 229 base::Time build_time = base::GetBuildTime(); |
111 if (time_now < build_time - base::TimeDelta::FromDays(2)) | 230 if (time_now < build_time - base::TimeDelta::FromDays(2)) |
112 return true; | 231 return true; |
113 return false; | 232 return false; |
114 } | 233 } |
115 | 234 |
116 bool SSLErrorClassification::IsUserClockInTheFuture(base::Time time_now) { | 235 bool SSLErrorClassification::IsUserClockInTheFuture(base::Time time_now) { |
117 base::Time build_time = base::GetBuildTime(); | 236 base::Time build_time = base::GetBuildTime(); |
118 if (time_now > build_time + base::TimeDelta::FromDays(365)) | 237 if (time_now > build_time + base::TimeDelta::FromDays(365)) |
119 return true; | 238 return true; |
120 return false; | 239 return false; |
121 } | 240 } |
122 | 241 |
123 bool SSLErrorClassification::IsWindowsVersionSP3OrLower() { | 242 bool SSLErrorClassification::IsWindowsVersionSP3OrLower() { |
124 #if defined(OS_WIN) | 243 #if defined(OS_WIN) |
125 const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); | 244 const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); |
126 base::win::OSInfo::ServicePack service_pack = os_info->service_pack(); | 245 base::win::OSInfo::ServicePack service_pack = os_info->service_pack(); |
127 if (os_info->version() < base::win::VERSION_VISTA && service_pack.major < 3) | 246 if (os_info->version() < base::win::VERSION_VISTA && service_pack.major < 3) |
128 return true; | 247 return true; |
129 #endif | 248 #endif |
130 return false; | 249 return false; |
131 } | 250 } |
132 | 251 |
133 void SSLErrorClassification::RecordUMAStatistics(bool overridable) { | 252 void SSLErrorClassification::Observe( |
134 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) | 253 int type, |
135 RecordSSLInterstitialCause(overridable, CLOCK_PAST); | 254 const content::NotificationSource& source, |
136 if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) | 255 const content::NotificationDetails& details) { |
137 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); | 256 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
257 // When detection is disabled, captive portal service always sends | |
258 // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case. | |
259 if (!captive_portal_detection_enabled_) | |
260 return; | |
261 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { | |
262 captive_portal_probe_completed_ = true; | |
263 CaptivePortalService::Results* results = | |
264 content::Details<CaptivePortalService::Results>( | |
265 details).ptr(); | |
266 // If a captive portal was detected at any point when the interstitial was | |
267 // displayed, assume that the interstitial was caused by a captive portal. | |
268 // Example scenario: | |
269 // 1- Interstitial displayed and captive portal detected, setting the flag. | |
270 // 2- Captive portal detection automatically opens portal login page. | |
271 // 3- User logs in on the portal login page. | |
272 // A notification will be received here for RESULT_INTERNET_CONNECTED. Make | |
273 // sure we don't clear the captive protal flag, since the interstitial was | |
274 // potentially caused by the captive portal. | |
275 captive_portal_detected_ = captive_portal_detected_ || | |
276 (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL); | |
277 // Also keep track of non-HTTP portals and error cases. | |
278 captive_portal_no_response_ = captive_portal_no_response_ || | |
279 (results->result == captive_portal::RESULT_NO_RESPONSE); | |
280 if (SSLErrorInfo::NetErrorToErrorType(cert_error_) == | |
281 SSLErrorInfo::CERT_DATE_INVALID) { | |
282 InvalidDateSeverityScore(); | |
radhikabhar
2014/07/28 23:02:35
Since the function for CalculateScoreEnvironments
| |
283 } | |
284 } | |
285 #endif | |
138 } | 286 } |
OLD | NEW |