• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/safe_browsing/ui_manager.h"
6 
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/url_request/url_request_context.h"
30 #include "net/url_request/url_request_context_getter.h"
31 
32 using content::BrowserThread;
33 using content::NavigationEntry;
34 using content::WebContents;
35 
36 struct SafeBrowsingUIManager::WhiteListedEntry {
37   int render_process_host_id;
38   int render_view_id;
39   std::string domain;
40   SBThreatType threat_type;
41 };
42 
UnsafeResource()43 SafeBrowsingUIManager::UnsafeResource::UnsafeResource()
44     : is_subresource(false),
45       threat_type(SB_THREAT_TYPE_SAFE),
46       render_process_host_id(-1),
47       render_view_id(-1) {
48 }
49 
~UnsafeResource()50 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
51 
SafeBrowsingUIManager(const scoped_refptr<SafeBrowsingService> & service)52 SafeBrowsingUIManager::SafeBrowsingUIManager(
53     const scoped_refptr<SafeBrowsingService>& service)
54     : sb_service_(service) {
55 }
56 
~SafeBrowsingUIManager()57 SafeBrowsingUIManager::~SafeBrowsingUIManager() { }
58 
StopOnIOThread(bool shutdown)59 void SafeBrowsingUIManager::StopOnIOThread(bool shutdown) {
60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
61 
62   if (shutdown)
63     sb_service_ = NULL;
64 }
65 
LogPauseDelay(base::TimeDelta time)66 void SafeBrowsingUIManager::LogPauseDelay(base::TimeDelta time) {
67   UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
68 }
69 
70 // Only report SafeBrowsing related stats when UMA is enabled. User must also
71 // ensure that safe browsing is enabled from the calling profile.
CanReportStats() const72 bool SafeBrowsingUIManager::CanReportStats() const {
73   const metrics::MetricsService* metrics = g_browser_process->metrics_service();
74   return metrics && metrics->reporting_active();
75 }
76 
OnBlockingPageDone(const std::vector<UnsafeResource> & resources,bool proceed)77 void SafeBrowsingUIManager::OnBlockingPageDone(
78     const std::vector<UnsafeResource>& resources,
79     bool proceed) {
80   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
81   for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
82        iter != resources.end(); ++iter) {
83     const UnsafeResource& resource = *iter;
84     if (!resource.callback.is_null())
85       resource.callback.Run(proceed);
86 
87     if (proceed) {
88       BrowserThread::PostTask(
89           BrowserThread::UI,
90           FROM_HERE,
91           base::Bind(&SafeBrowsingUIManager::UpdateWhitelist, this, resource));
92     }
93   }
94 }
95 
DisplayBlockingPage(const UnsafeResource & resource)96 void SafeBrowsingUIManager::DisplayBlockingPage(
97     const UnsafeResource& resource) {
98   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99 
100   if (!resource.threat_metadata.empty() &&
101       resource.threat_type == SB_THREAT_TYPE_URL_MALWARE) {
102     safe_browsing::MalwarePatternType proto;
103     // Malware sites tagged as "landing site" should only show a warning for a
104     // main-frame or sub-frame resource. (See "Types of Malware sites" under
105     // https://developers.google.com/safe-browsing/developers_guide_v3#UserWarnings)
106     if (proto.ParseFromString(resource.threat_metadata) &&
107         proto.pattern_type() == safe_browsing::MalwarePatternType::LANDING &&
108         resource.is_subresource && !resource.is_subframe) {
109       if (!resource.callback.is_null()) {
110         BrowserThread::PostTask(
111             BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
112       }
113       return;
114     }
115   }
116 
117   // Indicate to interested observers that the resource in question matched the
118   // SB filters. If the resource is already whitelisted, OnSafeBrowsingHit
119   // won't be called.
120   if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
121     FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingMatch(resource));
122   }
123 
124   // Check if the user has already ignored our warning for this render_view
125   // and domain.
126   if (IsWhitelisted(resource)) {
127     if (!resource.callback.is_null()) {
128       BrowserThread::PostTask(
129           BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
130     }
131     return;
132   }
133 
134   // The tab might have been closed.
135   WebContents* web_contents =
136       tab_util::GetWebContentsByID(resource.render_process_host_id,
137                                    resource.render_view_id);
138 
139   if (!web_contents) {
140     // The tab is gone and we did not have a chance at showing the interstitial.
141     // Just act as if "Don't Proceed" were chosen.
142     std::vector<UnsafeResource> resources;
143     resources.push_back(resource);
144     BrowserThread::PostTask(
145       BrowserThread::IO, FROM_HERE,
146       base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
147                  this, resources, false));
148     return;
149   }
150 
151   if (resource.threat_type != SB_THREAT_TYPE_SAFE &&
152       CanReportStats()) {
153     GURL page_url = web_contents->GetURL();
154     GURL referrer_url;
155     NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
156     if (entry)
157       referrer_url = entry->GetReferrer().url;
158 
159     // When the malicious url is on the main frame, and resource.original_url
160     // is not the same as the resource.url, that means we have a redirect from
161     // resource.original_url to resource.url.
162     // Also, at this point, page_url points to the _previous_ page that we
163     // were on. We replace page_url with resource.original_url and referrer
164     // with page_url.
165     if (!resource.is_subresource &&
166         !resource.original_url.is_empty() &&
167         resource.original_url != resource.url) {
168       referrer_url = page_url;
169       page_url = resource.original_url;
170     }
171     ReportSafeBrowsingHit(resource.url, page_url, referrer_url,
172                           resource.is_subresource, resource.threat_type,
173                           std::string() /* post_data */);
174   }
175   if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
176     FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingHit(resource));
177   }
178   SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
179 }
180 
181 // A safebrowsing hit is sent after a blocking page for malware/phishing
182 // or after the warning dialog for download urls, only for UMA users.
ReportSafeBrowsingHit(const GURL & malicious_url,const GURL & page_url,const GURL & referrer_url,bool is_subresource,SBThreatType threat_type,const std::string & post_data)183 void SafeBrowsingUIManager::ReportSafeBrowsingHit(
184     const GURL& malicious_url,
185     const GURL& page_url,
186     const GURL& referrer_url,
187     bool is_subresource,
188     SBThreatType threat_type,
189     const std::string& post_data) {
190   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
191   if (!CanReportStats())
192     return;
193 
194   BrowserThread::PostTask(
195       BrowserThread::IO, FROM_HERE,
196       base::Bind(&SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread, this,
197                  malicious_url, page_url, referrer_url, is_subresource,
198                  threat_type, post_data));
199 }
200 
AddObserver(Observer * observer)201 void SafeBrowsingUIManager::AddObserver(Observer* observer) {
202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203   observer_list_.AddObserver(observer);
204 }
205 
RemoveObserver(Observer * observer)206 void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208   observer_list_.RemoveObserver(observer);
209 }
210 
ReportSafeBrowsingHitOnIOThread(const GURL & malicious_url,const GURL & page_url,const GURL & referrer_url,bool is_subresource,SBThreatType threat_type,const std::string & post_data)211 void SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread(
212     const GURL& malicious_url,
213     const GURL& page_url,
214     const GURL& referrer_url,
215     bool is_subresource,
216     SBThreatType threat_type,
217     const std::string& post_data) {
218   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219 
220   // The service may delete the ping manager (i.e. when user disabling service,
221   // etc). This happens on the IO thread.
222   if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
223     return;
224 
225   DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
226            << " " << referrer_url << " " << is_subresource << " "
227            << threat_type;
228   sb_service_->ping_manager()->ReportSafeBrowsingHit(
229       malicious_url, page_url,
230       referrer_url, is_subresource,
231       threat_type, post_data);
232 }
233 
234 // If the user had opted-in to send MalwareDetails, this gets called
235 // when the report is ready.
SendSerializedMalwareDetails(const std::string & serialized)236 void SafeBrowsingUIManager::SendSerializedMalwareDetails(
237     const std::string& serialized) {
238   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
239 
240   // The service may delete the ping manager (i.e. when user disabling service,
241   // etc). This happens on the IO thread.
242   if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
243     return;
244 
245   if (!serialized.empty()) {
246     DVLOG(1) << "Sending serialized malware details.";
247     sb_service_->ping_manager()->ReportMalwareDetails(serialized);
248   }
249 }
250 
UpdateWhitelist(const UnsafeResource & resource)251 void SafeBrowsingUIManager::UpdateWhitelist(const UnsafeResource& resource) {
252   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
253   // Whitelist this domain and warning type for the given tab.
254   WhiteListedEntry entry;
255   entry.render_process_host_id = resource.render_process_host_id;
256   entry.render_view_id = resource.render_view_id;
257   entry.domain = net::registry_controlled_domains::GetDomainAndRegistry(
258       resource.url,
259       net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
260   entry.threat_type = resource.threat_type;
261   white_listed_entries_.push_back(entry);
262 }
263 
IsWhitelisted(const UnsafeResource & resource)264 bool SafeBrowsingUIManager::IsWhitelisted(const UnsafeResource& resource) {
265   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
266   // Check if the user has already ignored our warning for this render_view
267   // and domain.
268   for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
269     const WhiteListedEntry& entry = white_listed_entries_[i];
270     if (entry.render_process_host_id == resource.render_process_host_id &&
271         entry.render_view_id == resource.render_view_id &&
272         // Threat type must be the same or they can either be client-side
273         // phishing/malware URL or a SafeBrowsing phishing/malware URL.
274         // If we show one type of phishing/malware warning we don't want to show
275         // a second phishing/malware warning.
276         (entry.threat_type == resource.threat_type ||
277          (entry.threat_type == SB_THREAT_TYPE_URL_PHISHING &&
278           resource.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) ||
279          (entry.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL &&
280           resource.threat_type == SB_THREAT_TYPE_URL_PHISHING) ||
281          (entry.threat_type == SB_THREAT_TYPE_URL_MALWARE &&
282           resource.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) ||
283          (entry.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL &&
284           resource.threat_type == SB_THREAT_TYPE_URL_MALWARE))) {
285       return entry.domain ==
286           net::registry_controlled_domains::GetDomainAndRegistry(
287               resource.url,
288               net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
289     }
290   }
291   return false;
292 }
293 
294