Home | History | Annotate | Download | only in safe_browsing
      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 
     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 
     50 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
     51 
     52 SafeBrowsingUIManager::SafeBrowsingUIManager(
     53     const scoped_refptr<SafeBrowsingService>& service)
     54     : sb_service_(service) {
     55 }
     56 
     57 SafeBrowsingUIManager::~SafeBrowsingUIManager() { }
     58 
     59 void SafeBrowsingUIManager::StopOnIOThread(bool shutdown) {
     60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     61 
     62   if (shutdown)
     63     sb_service_ = NULL;
     64 }
     65 
     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.
     72 bool SafeBrowsingUIManager::CanReportStats() const {
     73   const metrics::MetricsService* metrics = g_browser_process->metrics_service();
     74   return metrics && metrics->reporting_active();
     75 }
     76 
     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 
     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.
    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 
    201 void SafeBrowsingUIManager::AddObserver(Observer* observer) {
    202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    203   observer_list_.AddObserver(observer);
    204 }
    205 
    206 void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
    207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    208   observer_list_.RemoveObserver(observer);
    209 }
    210 
    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.
    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 
    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 
    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