Chromium Code Reviews| 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 |