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