Add domain request detection to incident reporting service.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / ui_manager.cc
blob382d103a3626dc006e0be749357e4ebb0f783662
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.
5 #include "chrome/browser/safe_browsing/ui_manager.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/debug/leak_tracker.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/safe_browsing/malware_details.h"
17 #include "chrome/browser/safe_browsing/metadata.pb.h"
18 #include "chrome/browser/safe_browsing/ping_manager.h"
19 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
20 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
21 #include "chrome/browser/tab_contents/tab_util.h"
22 #include "chrome/common/url_constants.h"
23 #include "components/metrics/metrics_service.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/web_contents.h"
28 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
29 #include "net/ssl/ssl_info.h"
30 #include "net/url_request/url_request_context.h"
31 #include "net/url_request/url_request_context_getter.h"
33 using content::BrowserThread;
34 using content::NavigationEntry;
35 using content::WebContents;
37 struct SafeBrowsingUIManager::WhiteListedEntry {
38 int render_process_host_id;
39 int render_view_id;
40 std::string domain;
41 SBThreatType threat_type;
44 SafeBrowsingUIManager::UnsafeResource::UnsafeResource()
45 : is_subresource(false),
46 threat_type(SB_THREAT_TYPE_SAFE),
47 render_process_host_id(-1),
48 render_view_id(-1) {
51 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
53 SafeBrowsingUIManager::SafeBrowsingUIManager(
54 const scoped_refptr<SafeBrowsingService>& service)
55 : sb_service_(service) {
58 SafeBrowsingUIManager::~SafeBrowsingUIManager() { }
60 void SafeBrowsingUIManager::StopOnIOThread(bool shutdown) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
63 if (shutdown)
64 sb_service_ = NULL;
67 void SafeBrowsingUIManager::LogPauseDelay(base::TimeDelta time) {
68 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
71 // Only report SafeBrowsing related stats when UMA is enabled. User must also
72 // ensure that safe browsing is enabled from the calling profile.
73 bool SafeBrowsingUIManager::CanReportStats() const {
74 const metrics::MetricsService* metrics = g_browser_process->metrics_service();
75 return metrics && metrics->reporting_active();
78 void SafeBrowsingUIManager::OnBlockingPageDone(
79 const std::vector<UnsafeResource>& resources,
80 bool proceed) {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
82 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
83 iter != resources.end(); ++iter) {
84 const UnsafeResource& resource = *iter;
85 if (!resource.callback.is_null())
86 resource.callback.Run(proceed);
88 if (proceed) {
89 BrowserThread::PostTask(
90 BrowserThread::UI,
91 FROM_HERE,
92 base::Bind(&SafeBrowsingUIManager::UpdateWhitelist, this, resource));
97 void SafeBrowsingUIManager::DisplayBlockingPage(
98 const UnsafeResource& resource) {
99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
100 if (resource.is_subresource && !resource.is_subframe) {
101 // Sites tagged as serving Unwanted Software should only show a warning for
102 // main-frame or sub-frame resource. Similar warning restrictions should be
103 // applied to malware sites tagged as "landing sites" (see "Types of
104 // Malware sites" under
105 // https://developers.google.com/safe-browsing/developers_guide_v3#UserWarnings).
106 safe_browsing::MalwarePatternType proto;
107 if (resource.threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
108 (resource.threat_type == SB_THREAT_TYPE_URL_MALWARE &&
109 !resource.threat_metadata.empty() &&
110 proto.ParseFromString(resource.threat_metadata) &&
111 proto.pattern_type() == safe_browsing::MalwarePatternType::LANDING)) {
112 if (!resource.callback.is_null()) {
113 BrowserThread::PostTask(
114 BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
116 return;
120 // For M40, the UwS warning may be gated to not show any UI.
121 const bool ping_only = resource.threat_type == SB_THREAT_TYPE_URL_UNWANTED
122 && safe_browsing_util::GetUnwantedTrialGroup() < safe_browsing_util::UWS_ON;
124 // Indicate to interested observers that the resource in question matched the
125 // SB filters, unless the UwS interstitial is in ping-only mode.
126 if (resource.threat_type != SB_THREAT_TYPE_SAFE && !ping_only) {
127 FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingMatch(resource));
130 // Check if the user has already ignored our warning for this render_view
131 // and domain.
132 if (IsWhitelisted(resource)) {
133 if (!resource.callback.is_null()) {
134 BrowserThread::PostTask(
135 BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
137 return;
140 // The tab might have been closed.
141 WebContents* web_contents =
142 tab_util::GetWebContentsByID(resource.render_process_host_id,
143 resource.render_view_id);
145 if (!web_contents) {
146 // The tab is gone and we did not have a chance at showing the interstitial.
147 // Just act as if "Don't Proceed" were chosen.
148 std::vector<UnsafeResource> resources;
149 resources.push_back(resource);
150 BrowserThread::PostTask(
151 BrowserThread::IO, FROM_HERE,
152 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
153 this, resources, false));
154 return;
157 if (resource.threat_type != SB_THREAT_TYPE_SAFE &&
158 CanReportStats()) {
159 GURL page_url = web_contents->GetURL();
160 GURL referrer_url;
161 NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
162 if (entry)
163 referrer_url = entry->GetReferrer().url;
165 // When the malicious url is on the main frame, and resource.original_url
166 // is not the same as the resource.url, that means we have a redirect from
167 // resource.original_url to resource.url.
168 // Also, at this point, page_url points to the _previous_ page that we
169 // were on. We replace page_url with resource.original_url and referrer
170 // with page_url.
171 if (!resource.is_subresource &&
172 !resource.original_url.is_empty() &&
173 resource.original_url != resource.url) {
174 referrer_url = page_url;
175 page_url = resource.original_url;
177 ReportSafeBrowsingHit(resource.url, page_url, referrer_url,
178 resource.is_subresource, resource.threat_type,
179 std::string() /* post_data */);
182 // If UwS interstitials are turned off, return here before showing UI.
183 if (ping_only) {
184 if (!resource.callback.is_null()) {
185 BrowserThread::PostTask(
186 BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
188 return;
191 if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
192 FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingHit(resource));
194 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
197 // A safebrowsing hit is sent after a blocking page for malware/phishing
198 // or after the warning dialog for download urls, only for UMA users.
199 void SafeBrowsingUIManager::ReportSafeBrowsingHit(
200 const GURL& malicious_url,
201 const GURL& page_url,
202 const GURL& referrer_url,
203 bool is_subresource,
204 SBThreatType threat_type,
205 const std::string& post_data) {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207 if (!CanReportStats())
208 return;
210 BrowserThread::PostTask(
211 BrowserThread::IO, FROM_HERE,
212 base::Bind(&SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread, this,
213 malicious_url, page_url, referrer_url, is_subresource,
214 threat_type, post_data));
217 void SafeBrowsingUIManager::ReportInvalidCertificateChain(
218 const std::string& hostname,
219 const net::SSLInfo& ssl_info,
220 const base::Closure& callback) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222 BrowserThread::PostTaskAndReply(
223 BrowserThread::IO, FROM_HERE,
224 base::Bind(
225 &SafeBrowsingUIManager::ReportInvalidCertificateChainOnIOThread, this,
226 hostname, ssl_info),
227 callback);
230 void SafeBrowsingUIManager::AddObserver(Observer* observer) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232 observer_list_.AddObserver(observer);
235 void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 observer_list_.RemoveObserver(observer);
240 void SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread(
241 const GURL& malicious_url,
242 const GURL& page_url,
243 const GURL& referrer_url,
244 bool is_subresource,
245 SBThreatType threat_type,
246 const std::string& post_data) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
249 // The service may delete the ping manager (i.e. when user disabling service,
250 // etc). This happens on the IO thread.
251 if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
252 return;
254 DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
255 << " " << referrer_url << " " << is_subresource << " "
256 << threat_type;
257 sb_service_->ping_manager()->ReportSafeBrowsingHit(
258 malicious_url, page_url,
259 referrer_url, is_subresource,
260 threat_type, post_data);
263 void SafeBrowsingUIManager::ReportInvalidCertificateChainOnIOThread(
264 const std::string& hostname,
265 const net::SSLInfo& ssl_info) {
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
268 // The service may delete the ping manager (i.e. when user disabling service,
269 // etc). This happens on the IO thread.
270 if (!sb_service_ || !sb_service_->ping_manager())
271 return;
273 sb_service_->ping_manager()->ReportInvalidCertificateChain(hostname,
274 ssl_info);
277 // If the user had opted-in to send MalwareDetails, this gets called
278 // when the report is ready.
279 void SafeBrowsingUIManager::SendSerializedMalwareDetails(
280 const std::string& serialized) {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
283 // The service may delete the ping manager (i.e. when user disabling service,
284 // etc). This happens on the IO thread.
285 if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
286 return;
288 if (!serialized.empty()) {
289 DVLOG(1) << "Sending serialized malware details.";
290 sb_service_->ping_manager()->ReportMalwareDetails(serialized);
294 void SafeBrowsingUIManager::UpdateWhitelist(const UnsafeResource& resource) {
295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
296 // Whitelist this domain and warning type for the given tab.
297 WhiteListedEntry entry;
298 entry.render_process_host_id = resource.render_process_host_id;
299 entry.render_view_id = resource.render_view_id;
300 entry.domain = net::registry_controlled_domains::GetDomainAndRegistry(
301 resource.url,
302 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
303 entry.threat_type = resource.threat_type;
304 white_listed_entries_.push_back(entry);
307 bool SafeBrowsingUIManager::IsWhitelisted(const UnsafeResource& resource) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309 // Check if the user has already ignored our warning for this render_view
310 // and domain.
311 for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
312 const WhiteListedEntry& entry = white_listed_entries_[i];
313 if (entry.render_process_host_id == resource.render_process_host_id &&
314 entry.render_view_id == resource.render_view_id &&
315 // Threat type must be the same or they can either be client-side
316 // phishing/malware URL or a SafeBrowsing phishing/malware URL.
317 // If we show one type of phishing/malware warning we don't want to show
318 // a second phishing/malware warning.
319 (entry.threat_type == resource.threat_type ||
320 (entry.threat_type == SB_THREAT_TYPE_URL_PHISHING &&
321 resource.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) ||
322 (entry.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL &&
323 resource.threat_type == SB_THREAT_TYPE_URL_PHISHING) ||
324 (entry.threat_type == SB_THREAT_TYPE_URL_MALWARE &&
325 resource.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) ||
326 (entry.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL &&
327 resource.threat_type == SB_THREAT_TYPE_URL_MALWARE))) {
328 return entry.domain ==
329 net::registry_controlled_domains::GetDomainAndRegistry(
330 resource.url,
331 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
334 return false;