Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "content/browser/ssl/ssl_manager.h" | 5 #include "content/browser/ssl/ssl_manager.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/supports_user_data.h" | 13 #include "base/supports_user_data.h" |
| 14 #include "content/browser/frame_host/navigation_entry_impl.h" | 14 #include "content/browser/frame_host/navigation_entry_impl.h" |
| 15 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 15 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 16 #include "content/browser/loader/resource_request_info_impl.h" | 16 #include "content/browser/loader/resource_request_info_impl.h" |
| 17 #include "content/browser/ssl/ssl_error_handler.h" | 17 #include "content/browser/ssl/ssl_error_handler.h" |
| 18 #include "content/browser/web_contents/web_contents_impl.h" | 18 #include "content/browser/web_contents/web_contents_impl.h" |
| 19 #include "content/public/browser/browser_context.h" | 19 #include "content/public/browser/browser_context.h" |
| 20 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
| 21 #include "content/public/browser/certificate_request_result_type.h" | 21 #include "content/public/browser/certificate_request_result_type.h" |
| 22 #include "content/public/browser/content_browser_client.h" | 22 #include "content/public/browser/content_browser_client.h" |
| 23 #include "content/public/browser/navigation_details.h" | 23 #include "content/public/browser/navigation_details.h" |
| 24 #include "content/public/browser/ssl_host_state_delegate.h" | 24 #include "content/public/browser/ssl_host_state_delegate.h" |
| 25 #include "content/public/browser/ssl_status.h" | |
| 26 #include "net/url_request/url_request.h" | 25 #include "net/url_request/url_request.h" |
| 27 | 26 |
| 28 namespace content { | 27 namespace content { |
| 29 | 28 |
| 30 namespace { | 29 namespace { |
| 31 | 30 |
| 32 const char kSSLManagerKeyName[] = "content_ssl_manager"; | 31 const char kSSLManagerKeyName[] = "content_ssl_manager"; |
| 33 | 32 |
| 34 // Events for UMA. Do not reorder or change! | 33 // Events for UMA. Do not reorder or change! |
| 35 enum SSLGoodCertSeenEvent { | 34 enum SSLGoodCertSeenEvent { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 int render_process_id, | 143 int render_process_id, |
| 145 int render_frame_id, | 144 int render_frame_id, |
| 146 const net::SSLInfo& ssl_info, | 145 const net::SSLInfo& ssl_info, |
| 147 bool fatal) { | 146 bool fatal) { |
| 148 OnSSLCertificateError(delegate, RESOURCE_TYPE_SUB_RESOURCE, url, | 147 OnSSLCertificateError(delegate, RESOURCE_TYPE_SUB_RESOURCE, url, |
| 149 base::Bind(&WebContentsImpl::FromRenderFrameHostID, | 148 base::Bind(&WebContentsImpl::FromRenderFrameHostID, |
| 150 render_process_id, render_frame_id), | 149 render_process_id, render_frame_id), |
| 151 ssl_info, fatal); | 150 ssl_info, fatal); |
| 152 } | 151 } |
| 153 | 152 |
| 154 // static | |
| 155 void SSLManager::NotifySSLInternalStateChanged(BrowserContext* context) { | |
| 156 SSLManagerSet* managers = static_cast<SSLManagerSet*>( | |
| 157 context->GetUserData(kSSLManagerKeyName)); | |
| 158 | |
| 159 for (std::set<SSLManager*>::iterator i = managers->get().begin(); | |
| 160 i != managers->get().end(); ++i) { | |
| 161 (*i)->UpdateEntry((*i)->controller()->GetLastCommittedEntry()); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 SSLManager::SSLManager(NavigationControllerImpl* controller) | 153 SSLManager::SSLManager(NavigationControllerImpl* controller) |
| 166 : controller_(controller), | 154 : controller_(controller), |
| 167 ssl_host_state_delegate_( | 155 ssl_host_state_delegate_( |
| 168 controller->GetBrowserContext()->GetSSLHostStateDelegate()) { | 156 controller->GetBrowserContext()->GetSSLHostStateDelegate()) { |
| 169 DCHECK(controller_); | 157 DCHECK(controller_); |
| 170 | 158 |
| 171 SSLManagerSet* managers = static_cast<SSLManagerSet*>( | 159 SSLManagerSet* managers = static_cast<SSLManagerSet*>( |
| 172 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName)); | 160 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName)); |
| 173 if (!managers) { | 161 if (!managers) { |
| 174 managers = new SSLManagerSet; | 162 managers = new SSLManagerSet; |
| 175 controller_->GetBrowserContext()->SetUserData(kSSLManagerKeyName, managers); | 163 controller_->GetBrowserContext()->SetUserData(kSSLManagerKeyName, managers); |
| 176 } | 164 } |
| 177 managers->get().insert(this); | 165 managers->get().insert(this); |
| 178 } | 166 } |
| 179 | 167 |
| 180 SSLManager::~SSLManager() { | 168 SSLManager::~SSLManager() { |
| 181 SSLManagerSet* managers = static_cast<SSLManagerSet*>( | 169 SSLManagerSet* managers = static_cast<SSLManagerSet*>( |
| 182 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName)); | 170 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName)); |
| 183 managers->get().erase(this); | 171 managers->get().erase(this); |
| 184 } | 172 } |
| 185 | 173 |
| 186 void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) { | 174 void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) { |
| 187 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); | 175 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); |
| 188 UpdateEntry(entry); | 176 int content_status_flags = 0; |
| 177 if (!details.is_main_frame) { | |
| 178 // If it wasn't a main-frame navigation, then carry over content | |
| 179 // status flags. (For example, the mixed content flag shouldn't | |
| 180 // clear because of a frame navigation.) | |
| 181 NavigationEntryImpl* previous_entry = | |
| 182 controller_->GetEntryAtIndex(details.previous_entry_index); | |
| 183 if (previous_entry) { | |
| 184 content_status_flags = previous_entry->GetSSL().content_status; | |
| 185 } | |
| 186 } | |
| 187 UpdateEntry(entry, content_status_flags); | |
| 189 // Always notify the WebContents that the SSL state changed when a | 188 // Always notify the WebContents that the SSL state changed when a |
| 190 // load is committed, in case the active navigation entry has changed. | 189 // load is committed, in case the active navigation entry has changed. |
| 191 NotifyDidChangeVisibleSSLState(); | 190 NotifyDidChangeVisibleSSLState(); |
| 192 } | 191 } |
| 193 | 192 |
| 194 void SSLManager::DidRunInsecureContent(const GURL& security_origin) { | 193 void SSLManager::DidDisplayMixedContent() { |
| 194 UpdateLastCommittedEntry(SSLStatus::DISPLAYED_INSECURE_CONTENT); | |
| 195 } | |
| 196 | |
| 197 void SSLManager::DidDisplayContentWithCertErrors() { | |
| 195 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); | 198 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); |
| 196 if (!entry) | 199 if (!entry) |
| 197 return; | 200 return; |
| 201 // Only record information about subresources with cert errors if the | |
| 202 // main page is HTTPS with a certificate. | |
| 203 if (entry->GetURL().SchemeIsCryptographic() && entry->GetSSL().certificate) { | |
| 204 UpdateLastCommittedEntry(SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 void SSLManager::DidShowPasswordInputOnHttp() { | |
| 209 UpdateLastCommittedEntry(SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 210 } | |
| 211 | |
| 212 void SSLManager::DidShowCreditCardInputOnHttp() { | |
| 213 UpdateLastCommittedEntry(SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP); | |
| 214 } | |
| 215 | |
| 216 void SSLManager::DidRunMixedContent(const GURL& security_origin) { | |
| 217 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); | |
| 218 if (!entry) | |
| 219 return; | |
| 198 | 220 |
| 199 SiteInstance* site_instance = entry->site_instance(); | 221 SiteInstance* site_instance = entry->site_instance(); |
| 200 if (!site_instance) | 222 if (!site_instance) |
| 201 return; | 223 return; |
| 202 | 224 |
| 203 if (ssl_host_state_delegate_) { | 225 if (ssl_host_state_delegate_) { |
| 204 ssl_host_state_delegate_->HostRanInsecureContent( | 226 ssl_host_state_delegate_->HostRanInsecureContent( |
| 205 security_origin.host(), site_instance->GetProcess()->GetID(), | 227 security_origin.host(), site_instance->GetProcess()->GetID(), |
| 206 SSLHostStateDelegate::MIXED_CONTENT); | 228 SSLHostStateDelegate::MIXED_CONTENT); |
| 207 } | 229 } |
| 208 UpdateEntry(entry); | 230 UpdateEntry(entry, 0); |
| 209 NotifySSLInternalStateChanged(controller_->GetBrowserContext()); | 231 NotifySSLInternalStateChanged(controller_->GetBrowserContext()); |
| 210 } | 232 } |
| 211 | 233 |
| 212 void SSLManager::DidRunContentWithCertErrors(const GURL& security_origin) { | 234 void SSLManager::DidRunContentWithCertErrors(const GURL& security_origin) { |
| 213 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); | 235 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); |
| 214 if (!entry) | 236 if (!entry) |
| 215 return; | 237 return; |
| 216 | 238 |
| 217 SiteInstance* site_instance = entry->site_instance(); | 239 SiteInstance* site_instance = entry->site_instance(); |
| 218 if (!site_instance) | 240 if (!site_instance) |
| 219 return; | 241 return; |
| 220 | 242 |
| 221 if (ssl_host_state_delegate_) { | 243 if (ssl_host_state_delegate_) { |
| 222 ssl_host_state_delegate_->HostRanInsecureContent( | 244 ssl_host_state_delegate_->HostRanInsecureContent( |
| 223 security_origin.host(), site_instance->GetProcess()->GetID(), | 245 security_origin.host(), site_instance->GetProcess()->GetID(), |
| 224 SSLHostStateDelegate::CERT_ERRORS_CONTENT); | 246 SSLHostStateDelegate::CERT_ERRORS_CONTENT); |
| 225 } | 247 } |
| 226 UpdateEntry(entry); | 248 UpdateEntry(entry, 0); |
| 227 NotifySSLInternalStateChanged(controller_->GetBrowserContext()); | 249 NotifySSLInternalStateChanged(controller_->GetBrowserContext()); |
| 228 } | 250 } |
| 229 | 251 |
| 230 void SSLManager::OnCertError(std::unique_ptr<SSLErrorHandler> handler) { | 252 void SSLManager::OnCertError(std::unique_ptr<SSLErrorHandler> handler) { |
| 231 bool expired_previous_decision = false; | 253 bool expired_previous_decision = false; |
| 232 // First we check if we know the policy for this error. | 254 // First we check if we know the policy for this error. |
| 233 DCHECK(handler->ssl_info().is_valid()); | 255 DCHECK(handler->ssl_info().is_valid()); |
| 234 SSLHostStateDelegate::CertJudgment judgment = | 256 SSLHostStateDelegate::CertJudgment judgment = |
| 235 ssl_host_state_delegate_ | 257 ssl_host_state_delegate_ |
| 236 ? ssl_host_state_delegate_->QueryPolicy( | 258 ? ssl_host_state_delegate_->QueryPolicy( |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 328 const net::SSLInfo& ssl_info = handler->ssl_info(); | 350 const net::SSLInfo& ssl_info = handler->ssl_info(); |
| 329 const GURL& request_url = handler->request_url(); | 351 const GURL& request_url = handler->request_url(); |
| 330 ResourceType resource_type = handler->resource_type(); | 352 ResourceType resource_type = handler->resource_type(); |
| 331 GetContentClient()->browser()->AllowCertificateError( | 353 GetContentClient()->browser()->AllowCertificateError( |
| 332 web_contents, cert_error, ssl_info, request_url, resource_type, | 354 web_contents, cert_error, ssl_info, request_url, resource_type, |
| 333 overridable, strict_enforcement, expired_previous_decision, | 355 overridable, strict_enforcement, expired_previous_decision, |
| 334 base::Bind(&OnAllowCertificate, base::Owned(handler.release()), | 356 base::Bind(&OnAllowCertificate, base::Owned(handler.release()), |
| 335 ssl_host_state_delegate_)); | 357 ssl_host_state_delegate_)); |
| 336 } | 358 } |
| 337 | 359 |
| 338 void SSLManager::UpdateEntry(NavigationEntryImpl* entry) { | 360 void SSLManager::UpdateEntry(NavigationEntryImpl* entry, |
| 361 int additional_content_status_flags) { | |
| 339 // We don't always have a navigation entry to update, for example in the | 362 // We don't always have a navigation entry to update, for example in the |
| 340 // case of the Web Inspector. | 363 // case of the Web Inspector. |
| 341 if (!entry) | 364 if (!entry) |
| 342 return; | 365 return; |
| 343 | 366 |
| 344 SSLStatus original_ssl_status = entry->GetSSL(); // Copy! | 367 SSLStatus original_ssl_status = entry->GetSSL(); // Copy! |
| 345 entry->GetSSL().initialized = true; | 368 entry->GetSSL().initialized = true; |
| 346 | 369 entry->GetSSL().content_status |= additional_content_status_flags; |
| 347 WebContentsImpl* web_contents_impl = | |
| 348 static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents()); | |
| 349 | |
| 350 // For sensitive inputs (password, credit card) on HTTP, do not clear | |
| 351 // the |content_status| flag when the WebContents no longer has the | |
| 352 // flag set. This is different from how DISPLAYED_INSECURE_CONTENT and | |
| 353 // DISPLAYED_CONTENT_WITH_CERT_ERRORS are handled below. For sensitive | |
| 354 // inputs on HTTP, once the NavigationEntry has been marked as having | |
| 355 // displayed a sensitive input, it stays that way, even if the | |
| 356 // sensitive input is subsequently removed from the page. | |
| 357 if (web_contents_impl->DisplayedPasswordFieldOnHttp()) { | |
| 358 entry->GetSSL().content_status |= | |
| 359 SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP; | |
| 360 } | |
| 361 | |
| 362 if (web_contents_impl->DisplayedCreditCardFieldOnHttp()) { | |
| 363 entry->GetSSL().content_status |= | |
| 364 SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP; | |
| 365 } | |
| 366 | |
| 367 // Do not record information about insecure subresources if the main | |
| 368 // page is HTTP or HTTPS without a certificate. | |
| 369 if (!entry->GetURL().SchemeIsCryptographic() || !entry->GetSSL().certificate) | |
| 370 return; | |
| 371 | |
| 372 // Update the entry's flags for insecure content. | |
| 373 if (!web_contents_impl->DisplayedInsecureContent()) | |
| 374 entry->GetSSL().content_status &= ~SSLStatus::DISPLAYED_INSECURE_CONTENT; | |
| 375 if (web_contents_impl->DisplayedInsecureContent()) | |
| 376 entry->GetSSL().content_status |= SSLStatus::DISPLAYED_INSECURE_CONTENT; | |
| 377 if (!web_contents_impl->DisplayedContentWithCertErrors()) { | |
| 378 entry->GetSSL().content_status &= | |
| 379 ~SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS; | |
| 380 } | |
| 381 if (web_contents_impl->DisplayedContentWithCertErrors()) { | |
| 382 entry->GetSSL().content_status |= | |
| 383 SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS; | |
| 384 } | |
| 385 | 370 |
| 386 SiteInstance* site_instance = entry->site_instance(); | 371 SiteInstance* site_instance = entry->site_instance(); |
| 387 // Note that |site_instance| can be NULL here because NavigationEntries don't | 372 // Note that |site_instance| can be NULL here because NavigationEntries don't |
| 388 // necessarily have site instances. Without a process, the entry can't | 373 // necessarily have site instances. Without a process, the entry can't |
| 389 // possibly have insecure content. See bug http://crbug.com/12423. | 374 // possibly have insecure content. See bug http://crbug.com/12423. |
| 390 if (site_instance && ssl_host_state_delegate_ && | 375 if (site_instance && ssl_host_state_delegate_ && |
| 391 ssl_host_state_delegate_->DidHostRunInsecureContent( | 376 ssl_host_state_delegate_->DidHostRunInsecureContent( |
| 392 entry->GetURL().host(), site_instance->GetProcess()->GetID(), | 377 entry->GetURL().host(), site_instance->GetProcess()->GetID(), |
| 393 SSLHostStateDelegate::MIXED_CONTENT)) { | 378 SSLHostStateDelegate::MIXED_CONTENT)) { |
| 394 entry->GetSSL().content_status |= SSLStatus::RAN_INSECURE_CONTENT; | 379 entry->GetSSL().content_status |= SSLStatus::RAN_INSECURE_CONTENT; |
| 395 } | 380 } |
| 396 | 381 |
| 397 if (site_instance && ssl_host_state_delegate_ && | 382 // Only record information about subresources with cert errors if the |
| 383 // main page is HTTPS with a certificate. | |
| 384 if (entry->GetURL().SchemeIsCryptographic() && entry->GetSSL().certificate && | |
| 385 site_instance && ssl_host_state_delegate_ && | |
| 398 ssl_host_state_delegate_->DidHostRunInsecureContent( | 386 ssl_host_state_delegate_->DidHostRunInsecureContent( |
| 399 entry->GetURL().host(), site_instance->GetProcess()->GetID(), | 387 entry->GetURL().host(), site_instance->GetProcess()->GetID(), |
| 400 SSLHostStateDelegate::CERT_ERRORS_CONTENT)) { | 388 SSLHostStateDelegate::CERT_ERRORS_CONTENT)) { |
| 401 entry->GetSSL().content_status |= SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS; | 389 entry->GetSSL().content_status |= SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS; |
| 402 } | 390 } |
| 403 | 391 |
| 404 if (!entry->GetSSL().Equals(original_ssl_status)) | 392 if (!entry->GetSSL().Equals(original_ssl_status)) |
| 405 NotifyDidChangeVisibleSSLState(); | 393 NotifyDidChangeVisibleSSLState(); |
| 406 } | 394 } |
| 407 | 395 |
| 396 void SSLManager::UpdateLastCommittedEntry(int additional_content_status_flags) { | |
| 397 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); | |
| 398 if (!entry) | |
| 399 return; | |
| 400 UpdateEntry(entry, additional_content_status_flags); | |
| 401 } | |
| 402 | |
| 408 void SSLManager::NotifyDidChangeVisibleSSLState() { | 403 void SSLManager::NotifyDidChangeVisibleSSLState() { |
| 409 WebContentsImpl* contents = | 404 WebContentsImpl* contents = |
| 410 static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents()); | 405 static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents()); |
| 411 contents->DidChangeVisibleSSLState(); | 406 contents->DidChangeVisibleSSLState(); |
| 412 } | 407 } |
| 413 | 408 |
| 409 // static | |
| 410 void SSLManager::NotifySSLInternalStateChanged(BrowserContext* context) { | |
|
estark
2016/10/12 19:21:26
A note about why this is private now: we were prev
| |
| 411 SSLManagerSet* managers = | |
| 412 static_cast<SSLManagerSet*>(context->GetUserData(kSSLManagerKeyName)); | |
| 413 | |
| 414 for (std::set<SSLManager*>::iterator i = managers->get().begin(); | |
| 415 i != managers->get().end(); ++i) { | |
| 416 (*i)->UpdateEntry((*i)->controller()->GetLastCommittedEntry(), 0); | |
| 417 } | |
| 418 } | |
| 419 | |
| 414 } // namespace content | 420 } // namespace content |
| OLD | NEW |