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 | |
| 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 |