ssl_blocking_page.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ssl/ssl_blocking_page.h" 6 7#include "base/i18n/rtl.h" 8#include "base/metrics/field_trial.h" 9#include "base/metrics/histogram.h" 10#include "base/strings/string_piece.h" 11#include "base/strings/utf_string_conversions.h" 12#include "base/values.h" 13#include "chrome/browser/history/history_service_factory.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/renderer_preferences_util.h" 16#include "chrome/browser/ssl/ssl_error_info.h" 17#include "chrome/browser/ui/browser.h" 18#include "chrome/browser/ui/browser_finder.h" 19#include "content/public/browser/cert_store.h" 20#include "content/public/browser/interstitial_page.h" 21#include "content/public/browser/navigation_controller.h" 22#include "content/public/browser/navigation_entry.h" 23#include "content/public/browser/notification_service.h" 24#include "content/public/browser/notification_types.h" 25#include "content/public/browser/render_process_host.h" 26#include "content/public/browser/render_view_host.h" 27#include "content/public/browser/web_contents.h" 28#include "content/public/common/ssl_status.h" 29#include "grit/app_locale_settings.h" 30#include "grit/browser_resources.h" 31#include "grit/generated_resources.h" 32#include "net/base/net_errors.h" 33#include "net/base/net_util.h" 34#include "ui/base/l10n/l10n_util.h" 35#include "ui/base/resource/resource_bundle.h" 36#include "ui/base/webui/jstemplate_builder.h" 37 38#if defined(OS_WIN) 39#include "base/win/windows_version.h" 40#endif 41 42using base::TimeTicks; 43using content::InterstitialPage; 44using content::NavigationController; 45using content::NavigationEntry; 46 47namespace { 48 49// These represent the commands sent by ssl_roadblock.html. 50enum SSLBlockingPageCommands { 51 CMD_DONT_PROCEED, 52 CMD_PROCEED, 53 CMD_FOCUS, 54 CMD_MORE 55}; 56 57// Events for UMA. 58enum SSLBlockingPageEvent { 59 SHOW_ALL, 60 SHOW_OVERRIDABLE, 61 PROCEED_OVERRIDABLE, 62 PROCEED_NAME, 63 PROCEED_DATE, 64 PROCEED_AUTHORITY, 65 DONT_PROCEED_OVERRIDABLE, 66 DONT_PROCEED_NAME, 67 DONT_PROCEED_DATE, 68 DONT_PROCEED_AUTHORITY, 69 MORE, 70 SHOW_UNDERSTAND, // Used by the summer 2013 Finch trial. Deprecated. 71 SHOW_INTERNAL_HOSTNAME, 72 PROCEED_INTERNAL_HOSTNAME, 73 SHOW_NEW_SITE, 74 PROCEED_NEW_SITE, 75 UNUSED_BLOCKING_PAGE_EVENT, 76}; 77 78void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) { 79 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl", 80 event, 81 UNUSED_BLOCKING_PAGE_EVENT); 82} 83 84void RecordSSLBlockingPageDetailedStats( 85 bool proceed, 86 int cert_error, 87 bool overridable, 88 bool internal, 89 const base::TimeTicks& start_time, 90 int num_visits) { 91 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", 92 SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM); 93 if (start_time.is_null() || !overridable) { 94 // A null start time will occur if the page never came into focus. 95 // Overridable is false if the user didn't have any option except to turn 96 // back. In either case, we don't want to record some of our metrics. 97 return; 98 } 99 if (num_visits == 0) 100 RecordSSLBlockingPageEventStats(SHOW_NEW_SITE); 101 if (proceed) { 102 RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE); 103 if (internal) 104 RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME); 105 if (num_visits == 0) 106 RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE); 107 } else if (!proceed) { 108 RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE); 109 } 110 SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error); 111 switch (type) { 112 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: { 113 if (proceed) 114 RecordSSLBlockingPageEventStats(PROCEED_NAME); 115 else 116 RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME); 117 break; 118 } 119 case SSLErrorInfo::CERT_DATE_INVALID: { 120 if (proceed) 121 RecordSSLBlockingPageEventStats(PROCEED_DATE); 122 else 123 RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE); 124 break; 125 } 126 case SSLErrorInfo::CERT_AUTHORITY_INVALID: { 127 if (proceed) 128 RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY); 129 else 130 RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY); 131 break; 132 } 133 default: { 134 break; 135 } 136 } 137} 138 139} // namespace 140 141// Note that we always create a navigation entry with SSL errors. 142// No error happening loading a sub-resource triggers an interstitial so far. 143SSLBlockingPage::SSLBlockingPage( 144 content::WebContents* web_contents, 145 int cert_error, 146 const net::SSLInfo& ssl_info, 147 const GURL& request_url, 148 bool overridable, 149 bool strict_enforcement, 150 const base::Callback<void(bool)>& callback) 151 : callback_(callback), 152 web_contents_(web_contents), 153 cert_error_(cert_error), 154 ssl_info_(ssl_info), 155 request_url_(request_url), 156 overridable_(overridable), 157 strict_enforcement_(strict_enforcement), 158 internal_(false), 159 num_visits_(-1) { 160 // For UMA stats. 161 if (net::IsHostnameNonUnique(request_url_.HostNoBrackets())) 162 internal_ = true; 163 RecordSSLBlockingPageEventStats(SHOW_ALL); 164 if (overridable_ && !strict_enforcement_) { 165 RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE); 166 if (internal_) 167 RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME); 168 HistoryService* history_service = HistoryServiceFactory::GetForProfile( 169 Profile::FromBrowserContext(web_contents->GetBrowserContext()), 170 Profile::EXPLICIT_ACCESS); 171 if (history_service) { 172 history_service->GetVisibleVisitCountToHost( 173 request_url_, 174 &request_consumer_, 175 base::Bind(&SSLBlockingPage::OnGotHistoryCount, 176 base::Unretained(this))); 177 } 178 } 179 180 interstitial_page_ = InterstitialPage::Create( 181 web_contents_, true, request_url, this); 182 display_start_time_ = TimeTicks(); 183 interstitial_page_->Show(); 184} 185 186SSLBlockingPage::~SSLBlockingPage() { 187 if (!callback_.is_null()) { 188 RecordSSLBlockingPageDetailedStats(false, 189 cert_error_, 190 overridable_ && !strict_enforcement_, 191 internal_, 192 display_start_time_, 193 num_visits_); 194 // The page is closed without the user having chosen what to do, default to 195 // deny. 196 NotifyDenyCertificate(); 197 } 198} 199 200std::string SSLBlockingPage::GetHTMLContents() { 201 // Let's build the html error page. 202 DictionaryValue strings; 203 SSLErrorInfo error_info = 204 SSLErrorInfo::CreateError(SSLErrorInfo::NetErrorToErrorType(cert_error_), 205 ssl_info_.cert.get(), 206 request_url_); 207 208 int resource_id = IDR_SSL_ROAD_BLOCK_HTML; 209 strings.SetString("headLine", error_info.title()); 210 strings.SetString("description", error_info.details()); 211 strings.SetString("moreInfoTitle", 212 l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE)); 213 SetExtraInfo(&strings, error_info.extra_information()); 214 215 strings.SetString("exit", 216 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_EXIT)); 217 218 if (overridable_ && !strict_enforcement_) { 219 strings.SetString("title", 220 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE)); 221 strings.SetString("proceed", 222 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_PROCEED)); 223 strings.SetString("reasonForNotProceeding", 224 l10n_util::GetStringUTF16( 225 IDS_SSL_BLOCKING_PAGE_SHOULD_NOT_PROCEED)); 226 strings.SetString("errorType", "overridable"); 227 } else { 228 strings.SetString("title", 229 l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_TITLE)); 230 if (strict_enforcement_) { 231 strings.SetString("reasonForNotProceeding", 232 l10n_util::GetStringUTF16( 233 IDS_SSL_ERROR_PAGE_CANNOT_PROCEED)); 234 } else { 235 strings.SetString("reasonForNotProceeding", std::string()); 236 } 237 strings.SetString("errorType", "notoverridable"); 238 } 239 240 strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr"); 241 242 base::StringPiece html( 243 ResourceBundle::GetSharedInstance().GetRawDataResource( 244 resource_id)); 245 246 return webui::GetI18nTemplateHtml(html, &strings); 247} 248 249void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) { 250 int cert_id = content::CertStore::GetInstance()->StoreCert( 251 ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID()); 252 253 entry->GetSSL().security_style = 254 content::SECURITY_STYLE_AUTHENTICATION_BROKEN; 255 entry->GetSSL().cert_id = cert_id; 256 entry->GetSSL().cert_status = ssl_info_.cert_status; 257 entry->GetSSL().security_bits = ssl_info_.security_bits; 258#if !defined(OS_ANDROID) 259 Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); 260 if (browser) 261 browser->VisibleSSLStateChanged(web_contents_); 262#endif // !defined(OS_ANDROID) 263} 264 265// Matches events defined in ssl_error.html and ssl_roadblock.html. 266void SSLBlockingPage::CommandReceived(const std::string& command) { 267 int cmd = atoi(command.c_str()); 268 if (cmd == CMD_DONT_PROCEED) { 269 interstitial_page_->DontProceed(); 270 } else if (cmd == CMD_PROCEED) { 271 interstitial_page_->Proceed(); 272 } else if (cmd == CMD_FOCUS) { 273 // Start recording the time when the page is first in focus 274 display_start_time_ = base::TimeTicks::Now(); 275 } else if (cmd == CMD_MORE) { 276 RecordSSLBlockingPageEventStats(MORE); 277 } 278} 279 280void SSLBlockingPage::OverrideRendererPrefs( 281 content::RendererPreferences* prefs) { 282 Profile* profile = Profile::FromBrowserContext( 283 web_contents_->GetBrowserContext()); 284 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile); 285} 286 287void SSLBlockingPage::OnProceed() { 288 RecordSSLBlockingPageDetailedStats(true, 289 cert_error_, 290 overridable_ && !strict_enforcement_, 291 internal_, 292 display_start_time_, 293 num_visits_); 294 // Accepting the certificate resumes the loading of the page. 295 NotifyAllowCertificate(); 296} 297 298void SSLBlockingPage::OnDontProceed() { 299 RecordSSLBlockingPageDetailedStats(false, 300 cert_error_, 301 overridable_ && !strict_enforcement_, 302 internal_, 303 display_start_time_, 304 num_visits_); 305 NotifyDenyCertificate(); 306} 307 308void SSLBlockingPage::NotifyDenyCertificate() { 309 // It's possible that callback_ may not exist if the user clicks "Proceed" 310 // followed by pressing the back button before the interstitial is hidden. 311 // In that case the certificate will still be treated as allowed. 312 if (callback_.is_null()) 313 return; 314 315 callback_.Run(false); 316 callback_.Reset(); 317} 318 319void SSLBlockingPage::NotifyAllowCertificate() { 320 DCHECK(!callback_.is_null()); 321 322 callback_.Run(true); 323 callback_.Reset(); 324} 325 326// static 327void SSLBlockingPage::SetExtraInfo( 328 DictionaryValue* strings, 329 const std::vector<string16>& extra_info) { 330 DCHECK_LT(extra_info.size(), 5U); // We allow 5 paragraphs max. 331 const char* keys[5] = { 332 "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5" 333 }; 334 int i; 335 for (i = 0; i < static_cast<int>(extra_info.size()); i++) { 336 strings->SetString(keys[i], extra_info[i]); 337 } 338 for (; i < 5; i++) { 339 strings->SetString(keys[i], std::string()); 340 } 341} 342 343void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle, 344 bool success, 345 int num_visits, 346 base::Time first_visit) { 347 num_visits_ = num_visits; 348} 349