diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 13:57:45 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-19 13:44:40 +0000 |
commit | 6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch) | |
tree | b87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc | |
parent | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff) | |
download | qtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz |
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc')
-rw-r--r-- | chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc | 355 |
1 files changed, 251 insertions, 104 deletions
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc index d75a56a3488..dfa868bdc33 100644 --- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc +++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc @@ -1,144 +1,291 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h" +#include <utility> #include <vector> +#include "base/metrics/histogram_macros.h" #include "base/timer/timer.h" -#include "components/safe_browsing_db/v4_local_database_manager.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "components/subresource_filter/content/browser/content_activation_list_utils.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h" +#include "components/subresource_filter/content/browser/subresource_filter_client.h" +#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" +#include "ui/base/page_transition_types.h" +#include "url/gurl.h" + +namespace subresource_filter { namespace { -// Maximum time in milliseconds to wait for the Safe Browsing service to -// verify a URL. After this amount of time the outstanding check will be -// aborted, and the URL will be treated as if it didn't belong to the -// Subresource Filter only list. -constexpr base::TimeDelta kCheckURLTimeout = base::TimeDelta::FromSeconds(5); +// Records histograms about the pattern of redirect chains, and about the +// pattern of whether the last URL in the chain matched the activation list. +#define REPORT_REDIRECT_PATTERN_FOR_SUFFIX(suffix, is_matched, chain_size) \ + do { \ + UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.PageLoad.FinalURLMatch." suffix, \ + is_matched); \ + if (is_matched) { \ + UMA_HISTOGRAM_COUNTS( \ + "SubresourceFilter.PageLoad.RedirectChainLength." suffix, \ + chain_size); \ + }; \ + } while (0) } // namespace -namespace subresource_filter { +SubresourceFilterSafeBrowsingActivationThrottle:: + SubresourceFilterSafeBrowsingActivationThrottle( + content::NavigationHandle* handle, + SubresourceFilterClient* client, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, + scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> + database_manager) + : NavigationThrottle(handle), + io_task_runner_(std::move(io_task_runner)), + // The throttle can be created without a valid database manager. If so, it + // becomes a pass-through throttle and should never defer. + database_client_(database_manager + ? new SubresourceFilterSafeBrowsingClient( + std::move(database_manager), + AsWeakPtr(), + io_task_runner_, + base::ThreadTaskRunnerHandle::Get()) + : nullptr, + base::OnTaskRunnerDeleter(io_task_runner_)), + client_(client) { + DCHECK(handle->IsInMainFrame()); +} + +SubresourceFilterSafeBrowsingActivationThrottle:: + ~SubresourceFilterSafeBrowsingActivationThrottle() { + // The last check could be ongoing when the navigation is cancelled. + if (check_results_.empty() || !check_results_.back().finished) + return; + // TODO(csharrison): Log more metrics based on check_results_. + RecordRedirectChainMatchPatternForList( + ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL); + RecordRedirectChainMatchPatternForList(ActivationList::PHISHING_INTERSTITIAL); + RecordRedirectChainMatchPatternForList(ActivationList::SUBRESOURCE_FILTER); +} + +bool SubresourceFilterSafeBrowsingActivationThrottle::NavigationIsPageReload( + content::NavigationHandle* handle) { + return ui::PageTransitionCoreTypeIs(handle->GetPageTransition(), + ui::PAGE_TRANSITION_RELOAD) || + // Some pages 'reload' from JavaScript by navigating to themselves. + handle->GetURL() == handle->GetReferrer().url; +} + +content::NavigationThrottle::ThrottleCheckResult +SubresourceFilterSafeBrowsingActivationThrottle::WillStartRequest() { + CheckCurrentUrl(); + return content::NavigationThrottle::ThrottleCheckResult::PROCEED; +} + +content::NavigationThrottle::ThrottleCheckResult +SubresourceFilterSafeBrowsingActivationThrottle::WillRedirectRequest() { + CheckCurrentUrl(); + return content::NavigationThrottle::ThrottleCheckResult::PROCEED; +} -class SubresourceFilterSafeBrowsingActivationThrottle::SBDatabaseClient - : public safe_browsing::SafeBrowsingDatabaseManager::Client { - public: - SBDatabaseClient( - scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> - database_manager, - base::WeakPtr<SubresourceFilterSafeBrowsingActivationThrottle> throttle, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) - : database_manager_(std::move(database_manager)), - throttle_(throttle), - io_task_runner_(io_task_runner) {} - - ~SBDatabaseClient() override { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - database_manager_->CancelCheck(this); +content::NavigationThrottle::ThrottleCheckResult +SubresourceFilterSafeBrowsingActivationThrottle::WillProcessResponse() { + // No need to defer the navigation if the check already happened. + if (!database_client_ || check_results_.back().finished) { + NotifyResult(); + return content::NavigationThrottle::ThrottleCheckResult::PROCEED; } + defer_time_ = base::TimeTicks::Now(); + return content::NavigationThrottle::ThrottleCheckResult::DEFER; +} + +const char* +SubresourceFilterSafeBrowsingActivationThrottle::GetNameForLogging() { + return "SubresourceFilterSafeBrowsingActivationThrottle"; +} + +void SubresourceFilterSafeBrowsingActivationThrottle::OnCheckUrlResultOnUI( + const SubresourceFilterSafeBrowsingClient::CheckResult& result) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + size_t request_id = result.request_id; + DCHECK_LT(request_id, check_results_.size()); - void CheckUrlOnIO(const GURL& url) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - DCHECK(!url.is_empty()); - url_being_checked_ = url; - if (database_manager_->CheckUrlForSubresourceFilter(url, this)) { - OnCheckBrowseUrlResult(url, safe_browsing::SB_THREAT_TYPE_SAFE, - safe_browsing::ThreatMetadata()); - return; - } - timer_.Start(FROM_HERE, kCheckURLTimeout, this, - &SubresourceFilterSafeBrowsingActivationThrottle:: - SBDatabaseClient::OnCheckUrlTimeout); + auto& stored_result = check_results_.at(request_id); + DCHECK(!stored_result.finished); + stored_result = result; + if (!defer_time_.is_null() && request_id == check_results_.size() - 1) { + NotifyResult(); + navigation_handle()->Resume(); } +} - void OnCheckBrowseUrlResult( - const GURL& url, - safe_browsing::SBThreatType threat_type, - const safe_browsing::ThreatMetadata& metadata) override { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - DCHECK_EQ(url_being_checked_, url); - timer_.Stop(); // Cancel the timeout timer. - io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&SubresourceFilterSafeBrowsingActivationThrottle:: - OnCheckUrlResultOnUI, - throttle_, url, threat_type, metadata.threat_pattern_type)); +void SubresourceFilterSafeBrowsingActivationThrottle::CheckCurrentUrl() { + if (!database_client_) + return; + check_results_.emplace_back(); + size_t id = check_results_.size() - 1; + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&SubresourceFilterSafeBrowsingClient::CheckUrlOnIO, + base::Unretained(database_client_.get()), + navigation_handle()->GetURL(), id)); +} + +void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() { + auto* driver_factory = ContentSubresourceFilterDriverFactory::FromWebContents( + navigation_handle()->GetWebContents()); + DCHECK(driver_factory); + if (driver_factory->GetActivationOptionsForLastCommittedPageLoad() + .should_whitelist_site_on_reload && + NavigationIsPageReload(navigation_handle())) { + // Whitelist this host for the current as well as subsequent navigations. + client_->WhitelistInCurrentWebContents(navigation_handle()->GetURL()); } - // Callback for when the safe browsing check has taken longer than - // kCheckURLTimeout. - void OnCheckUrlTimeout() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - database_manager_->CancelCheck(this); + Configuration::ActivationOptions matched_options; + ActivationDecision activation_decision = ComputeActivation(&matched_options); + + // Check for whitelisted status last, so that the client gets an accurate + // indication of whether there would be activation otherwise. + bool whitelisted = client_->OnPageActivationComputed( + navigation_handle(), + matched_options.activation_level == ActivationLevel::ENABLED); - OnCheckBrowseUrlResult(url_being_checked_, - safe_browsing::SB_THREAT_TYPE_SAFE, - safe_browsing::ThreatMetadata()); + // Only reset the activation decision reason if we would have activated. + if (whitelisted && activation_decision == ActivationDecision::ACTIVATED) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ActivationWhitelisted"); + activation_decision = ActivationDecision::URL_WHITELISTED; + matched_options = Configuration::ActivationOptions(); } - private: - scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_; + driver_factory->NotifyPageActivationComputed( + navigation_handle(), activation_decision, matched_options); - // Timer to abort the safe browsing check if it takes too long. - base::OneShotTimer timer_; - GURL url_being_checked_; + base::TimeDelta delay = defer_time_.is_null() + ? base::TimeDelta::FromMilliseconds(0) + : base::TimeTicks::Now() - defer_time_; + UMA_HISTOGRAM_TIMES("SubresourceFilter.PageLoad.SafeBrowsingDelay", delay); - base::WeakPtr<SubresourceFilterSafeBrowsingActivationThrottle> throttle_; - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Log a histogram for the delay we would have introduced if the throttle only + // speculatively checks URLs on WillStartRequest. This is only different from + // the actual delay if there was at least one redirect. + base::TimeDelta no_redirect_speculation_delay = + check_results_.size() > 1 ? check_results_.back().check_time : delay; + UMA_HISTOGRAM_TIMES( + "SubresourceFilter.PageLoad.SafeBrowsingDelay.NoRedirectSpeculation", + no_redirect_speculation_delay); +} - DISALLOW_COPY_AND_ASSIGN(SBDatabaseClient); -}; +ActivationDecision +SubresourceFilterSafeBrowsingActivationThrottle::ComputeActivation( + Configuration::ActivationOptions* options) { + const GURL& url(navigation_handle()->GetURL()); + ActivationList matched_list = ActivationList::NONE; + DCHECK(!database_client_ || !check_results_.empty()); + if (!check_results_.empty()) { + DCHECK(check_results_.back().finished); + matched_list = GetListForThreatTypeAndMetadata( + check_results_.back().threat_type, check_results_.back().pattern_type); + } -SubresourceFilterSafeBrowsingActivationThrottle:: - SubresourceFilterSafeBrowsingActivationThrottle( - content::NavigationHandle* handle, - scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> - database_manager) - : NavigationThrottle(handle), - io_task_runner_(content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::IO)), - database_client_( - new SubresourceFilterSafeBrowsingActivationThrottle::SBDatabaseClient( - std::move(database_manager), - AsWeakPtr(), - base::ThreadTaskRunnerHandle::Get()), - base::OnTaskRunnerDeleter(io_task_runner_)) {} + const auto config_list = GetEnabledConfigurations(); + bool scheme_is_http_or_https = url.SchemeIsHTTPOrHTTPS(); + const auto highest_priority_activated_config = + std::find_if(config_list->configs_by_decreasing_priority().begin(), + config_list->configs_by_decreasing_priority().end(), + [&url, scheme_is_http_or_https, matched_list, + this](const Configuration& config) { + return DoesMainFrameURLSatisfyActivationConditions( + url, scheme_is_http_or_https, + config.activation_conditions, matched_list); + }); -SubresourceFilterSafeBrowsingActivationThrottle:: - ~SubresourceFilterSafeBrowsingActivationThrottle() {} + bool has_activated_config = + highest_priority_activated_config != + config_list->configs_by_decreasing_priority().end(); + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"), + "ContentSubresourceFilterDriverFactory::" + "ComputeActivationForMainFrameNavigation", + "highest_priority_activated_config", + has_activated_config + ? highest_priority_activated_config->ToTracedValue() + : base::MakeUnique<base::trace_event::TracedValue>()); -content::NavigationThrottle::ThrottleCheckResult -SubresourceFilterSafeBrowsingActivationThrottle::WillProcessResponse() { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&SubresourceFilterSafeBrowsingActivationThrottle:: - SBDatabaseClient::CheckUrlOnIO, - base::Unretained(database_client_.get()), - navigation_handle()->GetURL())); - return content::NavigationThrottle::ThrottleCheckResult::DEFER; + if (!has_activated_config) + return ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET; + + const Configuration::ActivationOptions activation_options = + highest_priority_activated_config->activation_options; + if (!scheme_is_http_or_https && + activation_options.activation_level != ActivationLevel::DISABLED) { + return ActivationDecision::UNSUPPORTED_SCHEME; + } + + *options = activation_options; + return activation_options.activation_level == ActivationLevel::DISABLED + ? ActivationDecision::ACTIVATION_DISABLED + : ActivationDecision::ACTIVATED; } -void SubresourceFilterSafeBrowsingActivationThrottle::OnCheckUrlResultOnUI( - const GURL& url, - safe_browsing::SBThreatType threat_type, - safe_browsing::ThreatPatternType pattern_type) { - content::WebContents* web_contents = navigation_handle()->GetWebContents(); - if (web_contents) { - using subresource_filter::ContentSubresourceFilterDriverFactory; - ContentSubresourceFilterDriverFactory* driver_factory = - ContentSubresourceFilterDriverFactory::FromWebContents(web_contents); - DCHECK(driver_factory); - - driver_factory->OnMainResourceMatchedSafeBrowsingBlacklist( - url, std::vector<GURL>(), threat_type, pattern_type); +bool SubresourceFilterSafeBrowsingActivationThrottle:: + DoesMainFrameURLSatisfyActivationConditions( + const GURL& url, + bool scheme_is_http_or_https, + const Configuration::ActivationConditions& conditions, + ActivationList matched_list) const { + switch (conditions.activation_scope) { + case ActivationScope::ALL_SITES: + return true; + case ActivationScope::ACTIVATION_LIST: + // ACTIVATION_LIST does not support non http/s URLs. + if (!scheme_is_http_or_https) + return false; + if (conditions.activation_list == matched_list) + return true; + if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL && + matched_list == ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL) { + // Handling special case, where activation on the phishing sites also + // mean the activation on the sites with social engineering metadata. + return true; + } + return false; + case ActivationScope::NO_SITES: + return false; + } + NOTREACHED(); + return false; +} + +void SubresourceFilterSafeBrowsingActivationThrottle:: + RecordRedirectChainMatchPatternForList(ActivationList activation_list) { + DCHECK(check_results_.back().finished); + ActivationList matched_list = GetListForThreatTypeAndMetadata( + check_results_.back().threat_type, check_results_.back().pattern_type); + bool is_matched = matched_list == activation_list; + size_t chain_size = check_results_.size(); + switch (activation_list) { + case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL: + REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SocialEngineeringAdsInterstitial", + is_matched, chain_size); + break; + case ActivationList::PHISHING_INTERSTITIAL: + REPORT_REDIRECT_PATTERN_FOR_SUFFIX("PhishingInterstitial", is_matched, + chain_size); + break; + case ActivationList::SUBRESOURCE_FILTER: + REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SubresourceFilterOnly", is_matched, + chain_size); + break; + default: + NOTREACHED(); + break; } - // TODO(https://crbug.com/704508): We should measure the delay introduces by - // this check. Similarly, as it's done the Safe Browsing Resource throttle. - navigation_handle()->Resume(); } } // namespace subresource_filter |