Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2149)

Unified Diff: chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.cc

Issue 859903002: Compare non-whitelisted off-domain inclusions against the browsing history. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@#c3_ODID_async
Patch Set: merge r312228 Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.cc
diff --git a/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.cc b/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.cc
index b083c2ea4d27769dd31d1915615c3ca780a9a5cc..7f8db67a729d79fd6a45d561f6e21592777904d1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.cc
@@ -7,14 +7,20 @@
#include <string>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/history/history_service.h"
+#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/database_manager.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
@@ -23,6 +29,30 @@ using content::BrowserThread;
namespace safe_browsing {
+namespace {
+
+// Returns a pointer to the Profile hosting the frame identified by
+// |render_process_id| and |render_frame_id| or NULL if the resolution can't be
grt (UTC plus 2) 2015/01/21 01:58:24 NULL -> null or nullptr as per chromium-dev discus
gab 2015/01/23 21:35:33 Done.
+// completed (e.g., the tab/renderer is gone by now). Must only be called on the
+// UI thread.
+Profile* GetProfileFromRenderFrameId(int render_process_id,
grt (UTC plus 2) 2015/01/21 01:58:24 teeny tiny nit: drop "Get" from the name, making t
gab 2015/01/23 21:35:33 Done.
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ if (!render_frame_host)
+ return nullptr;
+
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ if (!web_contents)
+ return nullptr;
+
+ return Profile::FromBrowserContext(web_contents->GetBrowserContext());
+}
+
+} // namespace
+
// A static data structure to carry information specific to a given off-domain
// inclusions across threads, this data will be readable even after the
// underlying request has been deleted.
@@ -31,6 +61,11 @@ struct OffDomainInclusionDetector::OffDomainInclusionInfo {
content::ResourceType resource_type;
+ // Render process and frame IDs, used to figure out which profile this request
+ // belongs to (from the UI thread) if later required during this analysis.
+ int render_process_id;
+ int render_frame_id;
+
// The URL of the off-domain inclusion.
GURL request_url;
@@ -47,14 +82,19 @@ struct OffDomainInclusionDetector::OffDomainInclusionInfo {
OffDomainInclusionDetector::OffDomainInclusionDetector(
const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager)
: OffDomainInclusionDetector(database_manager,
- ReportAnalysisEventCallback()) {
+ ReportAnalysisEventCallback(),
+ base::Bind(&GetProfileFromRenderFrameId)) {
}
OffDomainInclusionDetector::OffDomainInclusionDetector(
const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
- const ReportAnalysisEventCallback& report_analysis_event_callback)
+ const ReportAnalysisEventCallback& report_analysis_event_callback,
+ const GetProfileFromRenderFrameIdCallback&
+ get_profile_from_render_frame_id_callback)
: database_manager_(database_manager),
report_analysis_event_callback_(report_analysis_event_callback),
+ get_profile_from_render_frame_id_callback_(
+ get_profile_from_render_frame_id_callback),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_ptr_factory_(this) {
DCHECK(database_manager);
@@ -72,8 +112,17 @@ void OffDomainInclusionDetector::OnResourceRequest(
scoped_ptr<OffDomainInclusionInfo> off_domain_inclusion_info(
new OffDomainInclusionInfo);
+ const content::ResourceRequestInfo* resource_request_info =
+ content::ResourceRequestInfo::ForRequest(request);
+
off_domain_inclusion_info->resource_type =
- content::ResourceRequestInfo::ForRequest(request)->GetResourceType();
+ resource_request_info->GetResourceType();
+
+ bool has_associated_render_frame =
+ resource_request_info->GetAssociatedRenderFrame(
+ &off_domain_inclusion_info->render_process_id,
+ &off_domain_inclusion_info->render_frame_id);
+ DCHECK(has_associated_render_frame);
off_domain_inclusion_info->request_url = request->url();
@@ -146,14 +195,14 @@ void OffDomainInclusionDetector::BeginAnalysis(
// HTTPS => HTTP requests). Consider adding the original referrer to
// ResourceRequestInfo if that's an issue.
ReportAnalysisResult(off_domain_inclusion_info.Pass(),
- AnalysisEvent::EMPTY_MAIN_FRAME_URL);
+ AnalysisEvent::ABORT_EMPTY_MAIN_FRAME_URL);
} else {
// There is no reason for the main frame to start loading resources if its
// own URL is invalid but measure this in the wild to make sure.
// TODO(gab): UMA has proven that this never happens, remove this in a
// follow-up CL.
ReportAnalysisResult(off_domain_inclusion_info.Pass(),
- AnalysisEvent::INVALID_MAIN_FRAME_URL);
+ AnalysisEvent::ABORT_INVALID_MAIN_FRAME_URL);
}
return;
}
@@ -191,6 +240,69 @@ void OffDomainInclusionDetector::ContinueAnalysisOnWhitelistResult(
ReportAnalysisResult(off_domain_inclusion_info.Pass(),
AnalysisEvent::OFF_DOMAIN_INCLUSION_WHITELISTED);
} else {
+ ContinueAnalysisWithHistoryCheck(off_domain_inclusion_info.Pass());
+ }
+}
+
+void OffDomainInclusionDetector::ContinueAnalysisWithHistoryCheck(
+ scoped_ptr<const OffDomainInclusionInfo> off_domain_inclusion_info) {
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
+
+ // The |main_thread_task_runner_| is the UI thread in practice currently so
+ // this call can be made synchronously, but this would need to be made
+ // asynchronous should this ever change.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ Profile* profile = get_profile_from_render_frame_id_callback_.Run(
+ off_domain_inclusion_info->render_process_id,
+ off_domain_inclusion_info->render_frame_id);
+ if (!profile) {
+ ReportAnalysisResult(off_domain_inclusion_info.Pass(),
+ AnalysisEvent::ABORT_NO_PROFILE);
+ return;
+ } else if (profile->IsOffTheRecord()) {
+ ReportAnalysisResult(off_domain_inclusion_info.Pass(),
+ AnalysisEvent::ABORT_INCOGNITO);
+ return;
+ }
+
+ HistoryService* history_service =
+ HistoryServiceFactory::GetForProfileWithoutCreating(profile);
grt (UTC plus 2) 2015/01/21 01:58:24 My gut tells me that this should be GetForProfileI
gab 2015/01/23 21:35:33 It felt to me like, since I was explicitly checkin
grt (UTC plus 2) 2015/01/27 15:28:11 My concern is about correctness rather than overhe
gab 2015/01/28 19:33:06 Right, which is why I avoided using either IMPLICT
grt (UTC plus 2) 2015/01/28 21:10:50 If by "side-channel" you mean GetForProfileWithout
sky 2015/01/28 21:35:02 I don't have enough context about this code to tel
gab 2015/01/29 14:53:41 Apologies for the lack of context. tl;dr; we want
+
+ if (!history_service) {
+ // Should only happen very early during startup, receiving many such reports
+ // relative to other report types would indicate that something is wrong.
+ ReportAnalysisResult(off_domain_inclusion_info.Pass(),
+ AnalysisEvent::ABORT_NO_HISTORY_SERVICE);
+ return;
+ }
+
+ // Need to explicitly copy |request_url| here or this code would depend on
+ // parameter evaluation order as |off_domain_inclusion_info| is being handed
+ // off.
+ const GURL copied_request_url(off_domain_inclusion_info->request_url);
+ history_service->GetVisibleVisitCountToHost(
+ copied_request_url,
+ base::Bind(&OffDomainInclusionDetector::ContinueAnalysisOnHistoryResult,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(&off_domain_inclusion_info)),
+ &history_task_tracker_);
+}
+
+void OffDomainInclusionDetector::ContinueAnalysisOnHistoryResult(
+ scoped_ptr<const OffDomainInclusionInfo> off_domain_inclusion_info,
+ bool success,
+ int num_visits,
+ base::Time /* first_visit_time */) {
+ if (!success) {
+ ReportAnalysisResult(off_domain_inclusion_info.Pass(),
+ AnalysisEvent::ABORT_HISTORY_LOOKUP_FAILED);
+ return;
+ }
+
+ if (num_visits > 0) {
+ ReportAnalysisResult(off_domain_inclusion_info.Pass(),
+ AnalysisEvent::OFF_DOMAIN_INCLUSION_IN_HISTORY);
+ } else {
ReportAnalysisResult(off_domain_inclusion_info.Pass(),
AnalysisEvent::OFF_DOMAIN_INCLUSION_SUSPICIOUS);
}
@@ -207,30 +319,50 @@ void OffDomainInclusionDetector::ReportAnalysisResult(
off_domain_inclusion_info->resource_type,
content::RESOURCE_TYPE_LAST_TYPE);
+ // Log a histogram for the analysis result along with the associated
+ // ResourceType.
+ std::string histogram_name;
switch (analysis_event) {
case AnalysisEvent::NO_EVENT:
break;
- case AnalysisEvent::EMPTY_MAIN_FRAME_URL:
- UMA_HISTOGRAM_ENUMERATION("SBOffDomainInclusion.EmptyMainFrameURL",
- off_domain_inclusion_info->resource_type,
- content::RESOURCE_TYPE_LAST_TYPE);
+ case AnalysisEvent::ABORT_EMPTY_MAIN_FRAME_URL:
+ histogram_name = "SBOffDomainInclusion.Abort.EmptyMainFrameURL";
+ break;
+ case AnalysisEvent::ABORT_INVALID_MAIN_FRAME_URL:
+ // TODO(gab): This never occurs in practice, remove the code handling it.
+ break;
+ case AnalysisEvent::ABORT_NO_PROFILE:
+ histogram_name = "SBOffDomainInclusion.Abort.NoProfile";
break;
- case AnalysisEvent::INVALID_MAIN_FRAME_URL:
- UMA_HISTOGRAM_ENUMERATION("SBOffDomainInclusion.InvalidMainFrameURL",
- off_domain_inclusion_info->resource_type,
- content::RESOURCE_TYPE_LAST_TYPE);
+ case AnalysisEvent::ABORT_INCOGNITO:
+ histogram_name = "SBOffDomainInclusion.Abort.Incognito";
+ break;
+ case AnalysisEvent::ABORT_NO_HISTORY_SERVICE:
+ histogram_name = "SBOffDomainInclusion.Abort.NoHistoryService";
+ break;
+ case AnalysisEvent::ABORT_HISTORY_LOOKUP_FAILED:
+ histogram_name = "SBOffDomainInclusion.Abort.HistoryLookupFailed";
break;
case AnalysisEvent::OFF_DOMAIN_INCLUSION_WHITELISTED:
- UMA_HISTOGRAM_ENUMERATION("SBOffDomainInclusion.Whitelisted",
- off_domain_inclusion_info->resource_type,
- content::RESOURCE_TYPE_LAST_TYPE);
+ histogram_name = "SBOffDomainInclusion.Whitelisted";
+ break;
+ case AnalysisEvent::OFF_DOMAIN_INCLUSION_IN_HISTORY:
+ histogram_name = "SBOffDomainInclusion.InHistory";
break;
case AnalysisEvent::OFF_DOMAIN_INCLUSION_SUSPICIOUS:
- UMA_HISTOGRAM_ENUMERATION("SBOffDomainInclusion.Suspicious",
- off_domain_inclusion_info->resource_type,
- content::RESOURCE_TYPE_LAST_TYPE);
+ histogram_name = "SBOffDomainInclusion.Suspicious";
break;
}
+ if (!histogram_name.empty()) {
+ // Expanded from the UMA_HISTOGRAM_ENUMERATION macro.
+ base::LinearHistogram::FactoryGet(
+ histogram_name,
+ 1, // minimum,
+ content::RESOURCE_TYPE_LAST_TYPE, // maximum
+ content::RESOURCE_TYPE_LAST_TYPE + 1, // bucket_count
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+ ->Add(off_domain_inclusion_info->resource_type);
+ }
if (!report_analysis_event_callback_.is_null() &&
analysis_event != AnalysisEvent::NO_EVENT) {

Powered by Google App Engine
This is Rietveld 408576698