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"
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"
31 using content::BrowserThread
;
32 using content::NavigationEntry
;
33 using content::WebContents
;
35 struct SafeBrowsingUIManager::WhiteListedEntry
{
36 int render_process_host_id
;
39 SBThreatType threat_type
;
42 SafeBrowsingUIManager::UnsafeResource::UnsafeResource()
43 : is_subresource(false),
44 threat_type(SB_THREAT_TYPE_SAFE
),
45 render_process_host_id(-1),
49 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
51 SafeBrowsingUIManager::SafeBrowsingUIManager(
52 const scoped_refptr
<SafeBrowsingService
>& service
)
53 : sb_service_(service
) {
56 SafeBrowsingUIManager::~SafeBrowsingUIManager() { }
58 void SafeBrowsingUIManager::StopOnIOThread(bool shutdown
) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
65 void SafeBrowsingUIManager::LogPauseDelay(base::TimeDelta time
) {
66 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time
);
69 // Only report SafeBrowsing related stats when UMA is enabled. User must also
70 // ensure that safe browsing is enabled from the calling profile.
71 bool SafeBrowsingUIManager::CanReportStats() const {
72 const MetricsService
* metrics
= g_browser_process
->metrics_service();
73 return metrics
&& metrics
->reporting_active();
76 void SafeBrowsingUIManager::OnBlockingPageDone(
77 const std::vector
<UnsafeResource
>& resources
,
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
80 for (std::vector
<UnsafeResource
>::const_iterator iter
= resources
.begin();
81 iter
!= resources
.end(); ++iter
) {
82 const UnsafeResource
& resource
= *iter
;
83 if (!resource
.callback
.is_null())
84 resource
.callback
.Run(proceed
);
87 BrowserThread::PostTask(
90 base::Bind(&SafeBrowsingUIManager::UpdateWhitelist
, this, resource
));
95 void SafeBrowsingUIManager::DisplayBlockingPage(
96 const UnsafeResource
& resource
) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
99 // Indicate to interested observers that the resource in question matched the
100 // SB filters. If the resource is already whitelisted, OnSafeBrowsingHit
102 if (resource
.threat_type
!= SB_THREAT_TYPE_SAFE
) {
103 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnSafeBrowsingMatch(resource
));
106 // Check if the user has already ignored our warning for this render_view
108 if (IsWhitelisted(resource
)) {
109 if (!resource
.callback
.is_null()) {
110 BrowserThread::PostTask(
111 BrowserThread::IO
, FROM_HERE
, base::Bind(resource
.callback
, true));
116 // The tab might have been closed.
117 WebContents
* web_contents
=
118 tab_util::GetWebContentsByID(resource
.render_process_host_id
,
119 resource
.render_view_id
);
122 // The tab is gone and we did not have a chance at showing the interstitial.
123 // Just act as if "Don't Proceed" were chosen.
124 std::vector
<UnsafeResource
> resources
;
125 resources
.push_back(resource
);
126 BrowserThread::PostTask(
127 BrowserThread::IO
, FROM_HERE
,
128 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone
,
129 this, resources
, false));
133 if (resource
.threat_type
!= SB_THREAT_TYPE_SAFE
&&
135 GURL page_url
= web_contents
->GetURL();
137 NavigationEntry
* entry
= web_contents
->GetController().GetActiveEntry();
139 referrer_url
= entry
->GetReferrer().url
;
141 // When the malicious url is on the main frame, and resource.original_url
142 // is not the same as the resource.url, that means we have a redirect from
143 // resource.original_url to resource.url.
144 // Also, at this point, page_url points to the _previous_ page that we
145 // were on. We replace page_url with resource.original_url and referrer
147 if (!resource
.is_subresource
&&
148 !resource
.original_url
.is_empty() &&
149 resource
.original_url
!= resource
.url
) {
150 referrer_url
= page_url
;
151 page_url
= resource
.original_url
;
153 ReportSafeBrowsingHit(resource
.url
, page_url
, referrer_url
,
154 resource
.is_subresource
, resource
.threat_type
,
155 std::string() /* post_data */);
157 if (resource
.threat_type
!= SB_THREAT_TYPE_SAFE
) {
158 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnSafeBrowsingHit(resource
));
160 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource
);
163 // A safebrowsing hit is sent after a blocking page for malware/phishing
164 // or after the warning dialog for download urls, only for UMA users.
165 void SafeBrowsingUIManager::ReportSafeBrowsingHit(
166 const GURL
& malicious_url
,
167 const GURL
& page_url
,
168 const GURL
& referrer_url
,
170 SBThreatType threat_type
,
171 const std::string
& post_data
) {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
173 if (!CanReportStats())
176 BrowserThread::PostTask(
177 BrowserThread::IO
, FROM_HERE
,
178 base::Bind(&SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread
, this,
179 malicious_url
, page_url
, referrer_url
, is_subresource
,
180 threat_type
, post_data
));
183 void SafeBrowsingUIManager::AddObserver(Observer
* observer
) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
185 observer_list_
.AddObserver(observer
);
188 void SafeBrowsingUIManager::RemoveObserver(Observer
* observer
) {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
190 observer_list_
.RemoveObserver(observer
);
193 void SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread(
194 const GURL
& malicious_url
,
195 const GURL
& page_url
,
196 const GURL
& referrer_url
,
198 SBThreatType threat_type
,
199 const std::string
& post_data
) {
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
202 // The service may delete the ping manager (i.e. when user disabling service,
203 // etc). This happens on the IO thread.
204 if (sb_service_
.get() == NULL
|| sb_service_
->ping_manager() == NULL
)
207 DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url
<< " " << page_url
208 << " " << referrer_url
<< " " << is_subresource
<< " "
210 sb_service_
->ping_manager()->ReportSafeBrowsingHit(
211 malicious_url
, page_url
,
212 referrer_url
, is_subresource
,
213 threat_type
, post_data
);
216 // If the user had opted-in to send MalwareDetails, this gets called
217 // when the report is ready.
218 void SafeBrowsingUIManager::SendSerializedMalwareDetails(
219 const std::string
& serialized
) {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
222 // The service may delete the ping manager (i.e. when user disabling service,
223 // etc). This happens on the IO thread.
224 if (sb_service_
.get() == NULL
|| sb_service_
->ping_manager() == NULL
)
227 if (!serialized
.empty()) {
228 DVLOG(1) << "Sending serialized malware details.";
229 sb_service_
->ping_manager()->ReportMalwareDetails(serialized
);
233 void SafeBrowsingUIManager::UpdateWhitelist(const UnsafeResource
& resource
) {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
235 // Whitelist this domain and warning type for the given tab.
236 WhiteListedEntry entry
;
237 entry
.render_process_host_id
= resource
.render_process_host_id
;
238 entry
.render_view_id
= resource
.render_view_id
;
239 entry
.domain
= net::registry_controlled_domains::GetDomainAndRegistry(
241 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES
);
242 entry
.threat_type
= resource
.threat_type
;
243 white_listed_entries_
.push_back(entry
);
246 bool SafeBrowsingUIManager::IsWhitelisted(const UnsafeResource
& resource
) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
248 // Check if the user has already ignored our warning for this render_view
250 for (size_t i
= 0; i
< white_listed_entries_
.size(); ++i
) {
251 const WhiteListedEntry
& entry
= white_listed_entries_
[i
];
252 if (entry
.render_process_host_id
== resource
.render_process_host_id
&&
253 entry
.render_view_id
== resource
.render_view_id
&&
254 // Threat type must be the same or they can either be client-side
255 // phishing/malware URL or a SafeBrowsing phishing/malware URL.
256 // If we show one type of phishing/malware warning we don't want to show
257 // a second phishing/malware warning.
258 (entry
.threat_type
== resource
.threat_type
||
259 (entry
.threat_type
== SB_THREAT_TYPE_URL_PHISHING
&&
260 resource
.threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
) ||
261 (entry
.threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
&&
262 resource
.threat_type
== SB_THREAT_TYPE_URL_PHISHING
) ||
263 (entry
.threat_type
== SB_THREAT_TYPE_URL_MALWARE
&&
264 resource
.threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL
) ||
265 (entry
.threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL
&&
266 resource
.threat_type
== SB_THREAT_TYPE_URL_MALWARE
))) {
267 return entry
.domain
==
268 net::registry_controlled_domains::GetDomainAndRegistry(
270 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES
);