Commit 11279702 authored by meacer's avatar meacer Committed by Commit Bot

Add a new interstitial for blocked interception certs

This CL adds a new interstitial with custom strings and makes it
viewable from chrome://interstitials page. It does not yet hook into the
SSL error handler path to trigger the interstitial based on the new net
error.

Bug: 1014711
Change-Id: Ia66567cbb825c35910745aad181006041ae5b537
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1913882
Commit-Queue: Mustafa Emre Acer <meacer@chromium.org>
Reviewed-by: default avatarChristopher Thompson <cthomp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715520}
parent 58f24047
......@@ -1671,6 +1671,8 @@ jumbo_static_library("browser") {
"speech/tts_controller_delegate_impl.h",
"ssl/bad_clock_blocking_page.cc",
"ssl/bad_clock_blocking_page.h",
"ssl/blocked_interception_blocking_page.cc",
"ssl/blocked_interception_blocking_page.h",
"ssl/captive_portal_blocking_page.cc",
"ssl/captive_portal_blocking_page.h",
"ssl/captive_portal_helper.h",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ssl/blocked_interception_blocking_page.h"
#include "chrome/browser/interstitials/chrome_metrics_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/ssl/cert_report_helper.h"
#include "chrome/browser/ssl/ssl_error_controller_client.h"
#include "components/security_interstitials/content/ssl_cert_reporter.h"
#include "components/security_interstitials/core/metrics_helper.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
using content::InterstitialPageDelegate;
using content::NavigationController;
using content::NavigationEntry;
// static
const InterstitialPageDelegate::TypeID
BlockedInterceptionBlockingPage::kTypeForTesting =
&BlockedInterceptionBlockingPage::kTypeForTesting;
namespace {
const char kBlockedInterceptionMetricsName[] = "blocked_interception";
std::unique_ptr<ChromeMetricsHelper> CreateBlockedInterceptionMetricsHelper(
content::WebContents* web_contents,
const GURL& request_url) {
// Set up the metrics helper for the BlockedInterceptionUI.
security_interstitials::MetricsHelper::ReportDetails reporting_info;
reporting_info.metric_prefix = kBlockedInterceptionMetricsName;
std::unique_ptr<ChromeMetricsHelper> metrics_helper =
std::make_unique<ChromeMetricsHelper>(web_contents, request_url,
reporting_info);
metrics_helper.get()->StartRecordingCaptivePortalMetrics(false);
return metrics_helper;
}
} // namespace
// Note that we always create a navigation entry with SSL errors.
// No error happening loading a sub-resource triggers an interstitial so far.
// Creating an interstitial without showing (e.g. from chrome://interstitials)
// it leaks memory, so don't create it here.
BlockedInterceptionBlockingPage::BlockedInterceptionBlockingPage(
content::WebContents* web_contents,
int cert_error,
const GURL& request_url,
std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
const net::SSLInfo& ssl_info)
: SSLBlockingPageBase(
web_contents,
cert_error,
CertificateErrorReport::INTERSTITIAL_BLOCKED_INTERCEPTION,
ssl_info,
request_url,
std::move(ssl_cert_reporter),
true /* overridable */,
base::Time::Now(),
std::make_unique<SSLErrorControllerClient>(
web_contents,
ssl_info,
cert_error,
request_url,
CreateBlockedInterceptionMetricsHelper(web_contents,
request_url))),
ssl_info_(ssl_info),
blocked_interception_ui_(
new security_interstitials::BlockedInterceptionUI(request_url,
cert_error,
ssl_info,
controller())) {}
BlockedInterceptionBlockingPage::~BlockedInterceptionBlockingPage() = default;
bool BlockedInterceptionBlockingPage::ShouldCreateNewNavigation() const {
return true;
}
InterstitialPageDelegate::TypeID
BlockedInterceptionBlockingPage::GetTypeForTesting() {
return BlockedInterceptionBlockingPage::kTypeForTesting;
}
void BlockedInterceptionBlockingPage::PopulateInterstitialStrings(
base::DictionaryValue* load_time_data) {
blocked_interception_ui_->PopulateStringsForHTML(load_time_data);
cert_report_helper()->PopulateExtendedReportingOption(load_time_data);
}
void BlockedInterceptionBlockingPage::OverrideEntry(NavigationEntry* entry) {
entry->GetSSL() = content::SSLStatus(ssl_info_);
}
// This handles the commands sent from the interstitial JavaScript.
void BlockedInterceptionBlockingPage::CommandReceived(
const std::string& command) {
if (command == "\"pageLoadComplete\"") {
// content::WaitForRenderFrameReady sends this message when the page
// load completes. Ignore it.
return;
}
int cmd = 0;
bool retval = base::StringToInt(command, &cmd);
DCHECK(retval);
// Let the CertReportHelper handle commands first, This allows it to get set
// up to send reports, so that the report is populated properly if
// BlockedInterceptionUI's command handling triggers a report to be sent.
cert_report_helper()->HandleReportingCommands(
static_cast<security_interstitials::SecurityInterstitialCommand>(cmd),
controller()->GetPrefService());
blocked_interception_ui_->HandleCommand(
static_cast<security_interstitials::SecurityInterstitialCommand>(cmd));
}
void BlockedInterceptionBlockingPage::OverrideRendererPrefs(
blink::mojom::RendererPreferences* prefs) {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SSL_BLOCKED_INTERCEPTION_BLOCKING_PAGE_H_
#define CHROME_BROWSER_SSL_BLOCKED_INTERCEPTION_BLOCKING_PAGE_H_
#include "base/macros.h"
#include "chrome/browser/ssl/ssl_blocking_page_base.h"
#include "components/security_interstitials/content/ssl_cert_reporter.h"
#include "components/security_interstitials/core/blocked_interception_ui.h"
#include "net/ssl/ssl_info.h"
class BlockedInterceptionBlockingPage : public SSLBlockingPageBase {
public:
// Interstitial type, used in tests.
static const InterstitialPageDelegate::TypeID kTypeForTesting;
BlockedInterceptionBlockingPage(
content::WebContents* web_contents,
int cert_error,
const GURL& request_url,
std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
const net::SSLInfo& ssl_info);
~BlockedInterceptionBlockingPage() override;
// InterstitialPageDelegate method:
InterstitialPageDelegate::TypeID GetTypeForTesting() override;
protected:
// InterstitialPageDelegate implementation:
void CommandReceived(const std::string& command) override;
void OverrideEntry(content::NavigationEntry* entry) override;
void OverrideRendererPrefs(blink::mojom::RendererPreferences* prefs) override;
// SecurityInterstitialPage implementation:
bool ShouldCreateNewNavigation() const override;
void PopulateInterstitialStrings(
base::DictionaryValue* load_time_data) override;
private:
const net::SSLInfo ssl_info_;
const std::unique_ptr<security_interstitials::BlockedInterceptionUI>
blocked_interception_ui_;
DISALLOW_COPY_AND_ASSIGN(BlockedInterceptionBlockingPage);
};
#endif // CHROME_BROWSER_SSL_BLOCKED_INTERCEPTION_BLOCKING_PAGE_H_
......@@ -39,6 +39,9 @@ message CertLoggerInterstitialInfo {
INTERSTITIAL_SUPERFISH = 4 [deprecated = true];
// An interstitial telling the user to fix misconfigured MITM software.
INTERSTITIAL_MITM_SOFTWARE = 5;
// An interstitial telling the user that their connection is being
// intercepted by a known certificate.
INTERSTITIAL_BLOCKED_INTERCEPTION = 6;
}
// The type of interstitial that was shown
......
......@@ -269,6 +269,11 @@ void CertificateErrorReport::SetInterstitialInfo(
chrome_browser_ssl::CertLoggerInterstitialInfo::
INTERSTITIAL_MITM_SOFTWARE);
break;
case INTERSTITIAL_BLOCKED_INTERCEPTION:
interstitial_info->set_interstitial_reason(
chrome_browser_ssl::CertLoggerInterstitialInfo::
INTERSTITIAL_BLOCKED_INTERCEPTION);
break;
}
interstitial_info->set_user_proceeded(proceed_decision == USER_PROCEEDED);
......
......@@ -47,6 +47,7 @@ class CertificateErrorReport {
INTERSTITIAL_CLOCK = 3,
INTERSTITIAL_SUPERFISH = 4,
INTERSTITIAL_MITM_SOFTWARE = 5,
INTERSTITIAL_BLOCKED_INTERCEPTION = 6,
};
// Whether the user clicked through the interstitial or not.
......
......@@ -14,7 +14,6 @@
#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/security_interstitials/content/ssl_cert_reporter.h"
#include "components/security_interstitials/core/metrics_helper.h"
#include "components/security_interstitials/core/mitm_software_ui.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/navigation_controller.h"
......
......@@ -11,16 +11,13 @@
#include "base/macros.h"
#include "chrome/browser/ssl/ssl_blocking_page_base.h"
#include "components/security_interstitials/content/ssl_cert_reporter.h"
#include "components/security_interstitials/core/mitm_software_ui.h"
#include "components/ssl_errors/error_classification.h"
#include "content/public/browser/certificate_request_result_type.h"
#include "net/ssl/ssl_info.h"
class GURL;
namespace security_interstitials {
class MITMSoftwareUI;
}
// This class is responsible for showing/hiding the interstitial page that
// occurs when an SSL error is caused by any sort of MITM software. MITM
// software includes antiviruses, firewalls, proxies or any other non-malicious
......
......@@ -19,6 +19,7 @@
#include "chrome/browser/safe_browsing/test_safe_browsing_blocking_page_quiet.h"
#include "chrome/browser/safe_browsing/ui_manager.h"
#include "chrome/browser/ssl/bad_clock_blocking_page.h"
#include "chrome/browser/ssl/blocked_interception_blocking_page.h"
#include "chrome/browser/ssl/mitm_software_blocking_page.h"
#include "chrome/browser/ssl/ssl_blocking_page.h"
#include "chrome/common/buildflags.h"
......@@ -208,6 +209,17 @@ MITMSoftwareBlockingPage* CreateMITMSoftwareBlockingPage(
is_enterprise_managed);
}
BlockedInterceptionBlockingPage* CreateBlockedInterceptionBlockingPage(
content::WebContents* web_contents) {
const int cert_error = net::ERR_CERT_AUTHORITY_INVALID;
const GURL request_url("https://example.com");
net::SSLInfo ssl_info;
ssl_info.cert = ssl_info.unverified_cert = CreateFakeCert();
return new BlockedInterceptionBlockingPage(web_contents, cert_error,
request_url, nullptr, ssl_info);
}
BadClockBlockingPage* CreateBadClockBlockingPage(
content::WebContents* web_contents) {
// Set up a fake clock error.
......@@ -489,6 +501,9 @@ void InterstitialHTMLSource::StartDataRequest(
interstitial_delegate.reset(CreateSSLBlockingPage(web_contents));
} else if (path_without_query == "/mitm-software-ssl") {
interstitial_delegate.reset(CreateMITMSoftwareBlockingPage(web_contents));
} else if (path_without_query == "/blocked-interception") {
interstitial_delegate.reset(
CreateBlockedInterceptionBlockingPage(web_contents));
} else if (path_without_query == "/safebrowsing") {
interstitial_delegate.reset(CreateSafeBrowsingBlockingPage(web_contents));
} else if (path_without_query == "/clock") {
......
......@@ -186,6 +186,12 @@ IN_PROC_BROWSER_TEST_F(InterstitialUITest, OriginPolicyErrorInterstitial) {
base::ASCIIToUTF16("has requested that an origin policy"));
}
IN_PROC_BROWSER_TEST_F(InterstitialUITest, BlockedInterceptionInterstitial) {
TestInterstitial(GURL("chrome://interstitials/blocked-interception"),
"Your activity on example.com is being monitored",
base::ASCIIToUTF16("Anything you type"));
}
// Tests that back button works after opening an interstitial from
// chrome://interstitials.
IN_PROC_BROWSER_TEST_F(InterstitialUITest, InterstitialBackButton) {
......
......@@ -8,6 +8,8 @@ static_library("core") {
"bad_clock_ui.h",
"base_safe_browsing_error_ui.cc",
"base_safe_browsing_error_ui.h",
"blocked_interception_ui.cc",
"blocked_interception_ui.h",
"common_string_util.cc",
"common_string_util.h",
"controller_client.cc",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/security_interstitials/core/blocked_interception_ui.h"
#include "base/i18n/number_formatting.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/security_interstitials/core/common_string_util.h"
#include "components/security_interstitials/core/metrics_helper.h"
#include "components/ssl_errors/error_info.h"
#include "components/strings/grit/components_strings.h"
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
// Path to the relevant help center page.
const char kHelpPath[] = "answer/6098869";
} // namespace
namespace security_interstitials {
BlockedInterceptionUI::BlockedInterceptionUI(const GURL& request_url,
int cert_error,
const net::SSLInfo& ssl_info,
ControllerClient* controller)
: request_url_(request_url),
cert_error_(cert_error),
ssl_info_(ssl_info),
controller_(controller),
user_made_decision_(false) {
controller_->metrics_helper()->RecordUserInteraction(
security_interstitials::MetricsHelper::TOTAL_VISITS);
}
BlockedInterceptionUI::~BlockedInterceptionUI() {
// If the page is closing without an explicit decision, record it as not
// proceeding.
if (!user_made_decision_) {
controller_->metrics_helper()->RecordUserDecision(
MetricsHelper::DONT_PROCEED);
}
controller_->metrics_helper()->RecordShutdownMetrics();
}
void BlockedInterceptionUI::PopulateStringsForHTML(
base::DictionaryValue* load_time_data) {
CHECK(load_time_data);
// Shared with other SSL errors.
common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data);
common_string_util::PopulateSSLDebuggingStrings(
ssl_info_, base::Time::NowFromSystemTime(), load_time_data);
common_string_util::PopulateDarkModeDisplaySetting(load_time_data);
load_time_data->SetBoolean("overridable", true);
load_time_data->SetBoolean("hide_primary_button", false);
load_time_data->SetBoolean("bad_clock", false);
load_time_data->SetString("type", "BLOCKED_INTERCEPTION");
const base::string16 hostname(
common_string_util::GetFormattedHostName(request_url_));
// Set strings that are shared between enterprise and non-enterprise
// interstitials.
load_time_data->SetString(
"tabTitle",
l10n_util::GetStringFUTF16(IDS_BLOCKED_INTERCEPTION_HEADING, hostname));
load_time_data->SetString(
"heading",
l10n_util::GetStringFUTF16(IDS_BLOCKED_INTERCEPTION_HEADING, hostname));
load_time_data->SetString(
"primaryButtonText",
l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
load_time_data->SetString("finalParagraph", std::string());
load_time_data->SetString(
"primaryParagraph",
l10n_util::GetStringUTF16(IDS_BLOCKED_INTERCEPTION_PRIMARY_PARAGRAPH));
load_time_data->SetString(
"explanationParagraph",
l10n_util::GetStringUTF16(IDS_BLOCKED_INTERCEPTION_EXPLANATION));
load_time_data->SetString(
"finalParagraph", l10n_util::GetStringFUTF16(
IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH, hostname));
}
void BlockedInterceptionUI::HandleCommand(SecurityInterstitialCommand command) {
switch (command) {
case CMD_PROCEED: {
controller_->metrics_helper()->RecordUserDecision(MetricsHelper::PROCEED);
controller_->Proceed();
user_made_decision_ = true;
break;
}
case CMD_DO_REPORT:
controller_->SetReportingPreference(true);
break;
case CMD_DONT_REPORT:
controller_->SetReportingPreference(false);
break;
case CMD_SHOW_MORE_SECTION:
controller_->metrics_helper()->RecordUserInteraction(
security_interstitials::MetricsHelper::SHOW_ADVANCED);
break;
case CMD_OPEN_REPORTING_PRIVACY:
controller_->OpenExtendedReportingPrivacyPolicy(true);
break;
case CMD_OPEN_WHITEPAPER:
controller_->OpenExtendedReportingWhitepaper(true);
break;
case CMD_OPEN_HELP_CENTER: {
controller_->metrics_helper()->RecordUserInteraction(
security_interstitials::MetricsHelper::SHOW_LEARN_MORE);
// Add cert error code as a ref to support URL, this is used to expand the
// right section if the user is redirected to chrome://connection-help.
GURL::Replacements replacements;
// This has to be stored in a separate variable, otherwise asan throws a
// use-after-scope error
std::string cert_error_string =
base::UTF16ToUTF8(base::FormatNumber(cert_error_));
replacements.SetRefStr(cert_error_string);
// If |support_url_| is invalid, use the default help center url.
controller_->OpenUrlInNewForegroundTab(
controller_->GetBaseHelpCenterUrl()
.Resolve(kHelpPath)
.ReplaceComponents(replacements));
break;
}
case CMD_DONT_PROCEED:
case CMD_RELOAD:
case CMD_OPEN_DATE_SETTINGS:
case CMD_OPEN_DIAGNOSTIC:
case CMD_OPEN_LOGIN:
case CMD_REPORT_PHISHING_ERROR:
// Not supported by the SSL error page.
NOTREACHED() << "Unsupported command: " << command;
break;
case CMD_ERROR:
case CMD_TEXT_FOUND:
case CMD_TEXT_NOT_FOUND:
// Commands are for testing.
break;
}
}
} // namespace security_interstitials
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SECURITY_INTERSTITIALS_CORE_BLOCKED_INTERCEPTION_UI_H_
#define COMPONENTS_SECURITY_INTERSTITIALS_CORE_BLOCKED_INTERCEPTION_UI_H_
#include "base/macros.h"
#include "base/values.h"
#include "components/security_interstitials/core/controller_client.h"
#include "components/ssl_errors/error_classification.h"
#include "net/ssl/ssl_info.h"
#include "url/gurl.h"
namespace security_interstitials {
// Provides UI for SSL errors caused by blocked interceptions.
class BlockedInterceptionUI {
public:
BlockedInterceptionUI(const GURL& request_url,
int cert_error,
const net::SSLInfo& ssl_info,
ControllerClient* controller_);
~BlockedInterceptionUI();
void PopulateStringsForHTML(base::DictionaryValue* load_time_data);
void HandleCommand(SecurityInterstitialCommand command);
private:
const GURL request_url_;
const int cert_error_;
const net::SSLInfo ssl_info_;
ControllerClient* controller_;
bool user_made_decision_;
DISALLOW_COPY_AND_ASSIGN(BlockedInterceptionUI);
};
} // namespace security_interstitials
#endif // COMPONENTS_SECURITY_INTERSTITIALS_CORE_BLOCKED_INTERCEPTION_UI_H_
......@@ -72,6 +72,7 @@ function setupEvents() {
var billing = interstitialType == 'SAFEBROWSING' &&
loadTimeData.getBoolean('billing');
var originPolicy = interstitialType == "ORIGIN_POLICY";
var blockedInterception = interstitialType == "BLOCKED_INTERCEPTION";
var hidePrimaryButton = loadTimeData.getBoolean('hide_primary_button');
var showRecurrentErrorParagraph = loadTimeData.getBoolean(
'show_recurrent_error_paragraph');
......@@ -81,7 +82,7 @@ function setupEvents() {
$('body').classList.add('dark-mode-available');
}
if (ssl || originPolicy) {
if (ssl || originPolicy || blockedInterception) {
$('body').classList.add(badClock ? 'bad-clock' : 'ssl');
$('error-code').textContent = loadTimeData.getString('errorCode');
$('error-code').classList.remove(HIDDEN_CLASS);
......
......@@ -52,6 +52,9 @@
<li>
<a href="mitm-software-ssl?enterprise=1">MITM software on an enterprise-managed machine</a>
</li>
<li>
<a href="blocked-interception">Blocked interception</a>
</li>
</ul>
<h3>SafeBrowsing</h3>
<h4>Loud</h4>
......
......@@ -64,6 +64,26 @@
Applications that can cause this error include antivirus, firewall, and web-filtering or proxy software.
</message>
<message name="IDS_BLOCKED_INTERCEPTION_HEADING" desc="Large heading of the known interception interstitial.">
Your activity on <ph name="HOSTNAME">$1<ex>example.com</ex></ph> is being monitored
</message>
<message name="IDS_BLOCKED_INTERCEPTION_PRIMARY_PARAGRAPH" desc="Main paragraph of the known interception interstitial. A user visits a website, a known interception certificate intercepts their connection, and they are shown this error. Page title and additional description of the error are shown above.">
Anything you type, any pages you view, or any other activity on the web is being watched, and content on sites may be changed without your knowledge.
<ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>
</message>
<if expr="_google_chrome">
<message name="IDS_BLOCKED_INTERCEPTION_EXPLANATION" desc="Part of an extended description hidden behind an 'Advanced' button on an error page. A user visits a website, a known interception certificate intercepts their connection, and they are shown this error. Page title and additional description of the error are shown above.">
The certificate for this connection is not trusted by Google Chrome, because it is known to be used for network interception and monitoring.
</message>
</if>
<if expr="not _google_chrome">
<message name="IDS_BLOCKED_INTERCEPTION_EXPLANATION" desc="Part of an extended description hidden behind an 'Advanced' button on an error page. A user visits a website, a known interception certificate intercepts their connection, and they are shown this error. Page title and additional description of the error are shown above.">
The certificate for this connection is not trusted by Chromium, because it is known to be used for network interception and monitoring.
</message>
</if>
<!-- Lookalike URL warning -->
<message name="IDS_LOOKALIKE_URL_TITLE" desc="Tab title. Context: the requested URL might be trying to trick the user since it looks like a more popular URL. This interstitial points the user to the safe site instead.">
Did you mean <ph name="DOMAIN">$1<ex>example.com</ex></ph>?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment