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