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/safe_browsing_service.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/callback.h"
     12 #include "base/command_line.h"
     13 #include "base/debug/leak_tracker.h"
     14 #include "base/lazy_instance.h"
     15 #include "base/path_service.h"
     16 #include "base/prefs/pref_change_registrar.h"
     17 #include "base/prefs/pref_service.h"
     18 #include "base/stl_util.h"
     19 #include "base/strings/string_util.h"
     20 #include "base/threading/thread.h"
     21 #include "base/threading/thread_restrictions.h"
     22 #include "chrome/browser/browser_process.h"
     23 #include "chrome/browser/chrome_notification_types.h"
     24 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
     25 #include "chrome/browser/profiles/profile.h"
     26 #include "chrome/browser/profiles/profile_manager.h"
     27 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
     28 #include "chrome/browser/safe_browsing/database_manager.h"
     29 #include "chrome/browser/safe_browsing/download_protection_service.h"
     30 #include "chrome/browser/safe_browsing/incident_reporting_service.h"
     31 #include "chrome/browser/safe_browsing/malware_details.h"
     32 #include "chrome/browser/safe_browsing/ping_manager.h"
     33 #include "chrome/browser/safe_browsing/protocol_manager.h"
     34 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
     35 #include "chrome/browser/safe_browsing/ui_manager.h"
     36 #include "chrome/common/chrome_constants.h"
     37 #include "chrome/common/chrome_paths.h"
     38 #include "chrome/common/chrome_switches.h"
     39 #include "chrome/common/pref_names.h"
     40 #include "chrome/common/url_constants.h"
     41 #include "components/metrics/metrics_service.h"
     42 #include "components/startup_metric_utils/startup_metric_utils.h"
     43 #include "content/public/browser/browser_thread.h"
     44 #include "content/public/browser/cookie_crypto_delegate.h"
     45 #include "content/public/browser/cookie_store_factory.h"
     46 #include "content/public/browser/notification_service.h"
     47 #include "net/cookies/cookie_monster.h"
     48 #include "net/url_request/url_request_context.h"
     49 #include "net/url_request/url_request_context_getter.h"
     50 
     51 #if defined(OS_WIN)
     52 #include "chrome/installer/util/browser_distribution.h"
     53 #endif
     54 
     55 #if defined(OS_ANDROID)
     56 #include <string>
     57 #include "base/metrics/field_trial.h"
     58 #endif
     59 
     60 using content::BrowserThread;
     61 
     62 namespace {
     63 
     64 // Filename suffix for the cookie database.
     65 const base::FilePath::CharType kCookiesFile[] = FILE_PATH_LITERAL(" Cookies");
     66 
     67 // The default URL prefix where browser fetches chunk updates, hashes,
     68 // and reports safe browsing hits and malware details.
     69 const char* const kSbDefaultURLPrefix =
     70     "https://safebrowsing.google.com/safebrowsing";
     71 
     72 // The backup URL prefix used when there are issues establishing a connection
     73 // with the server at the primary URL.
     74 const char* const kSbBackupConnectErrorURLPrefix =
     75     "https://alt1-safebrowsing.google.com/safebrowsing";
     76 
     77 // The backup URL prefix used when there are HTTP-specific issues with the
     78 // server at the primary URL.
     79 const char* const kSbBackupHttpErrorURLPrefix =
     80     "https://alt2-safebrowsing.google.com/safebrowsing";
     81 
     82 // The backup URL prefix used when there are local network specific issues.
     83 const char* const kSbBackupNetworkErrorURLPrefix =
     84     "https://alt3-safebrowsing.google.com/safebrowsing";
     85 
     86 base::FilePath CookieFilePath() {
     87   return base::FilePath(
     88       SafeBrowsingService::GetBaseFilename().value() + kCookiesFile);
     89 }
     90 
     91 #if defined(FULL_SAFE_BROWSING)
     92 // Returns true if the incident reporting service is enabled via a field trial.
     93 bool IsIncidentReportingServiceEnabled() {
     94   const std::string group_name = base::FieldTrialList::FindFullName(
     95       "SafeBrowsingIncidentReportingService");
     96   return group_name == "Enabled";
     97 }
     98 #endif  // defined(FULL_SAFE_BROWSING)
     99 
    100 }  // namespace
    101 
    102 class SafeBrowsingURLRequestContextGetter
    103     : public net::URLRequestContextGetter {
    104  public:
    105   explicit SafeBrowsingURLRequestContextGetter(
    106       SafeBrowsingService* sb_service_);
    107 
    108   // Implementation for net::UrlRequestContextGetter.
    109   virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
    110   virtual scoped_refptr<base::SingleThreadTaskRunner>
    111       GetNetworkTaskRunner() const OVERRIDE;
    112 
    113  protected:
    114   virtual ~SafeBrowsingURLRequestContextGetter();
    115 
    116  private:
    117   SafeBrowsingService* const sb_service_;  // Owned by BrowserProcess.
    118   scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
    119 
    120   base::debug::LeakTracker<SafeBrowsingURLRequestContextGetter> leak_tracker_;
    121 };
    122 
    123 SafeBrowsingURLRequestContextGetter::SafeBrowsingURLRequestContextGetter(
    124     SafeBrowsingService* sb_service)
    125     : sb_service_(sb_service),
    126       network_task_runner_(
    127           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)) {
    128 }
    129 
    130 SafeBrowsingURLRequestContextGetter::~SafeBrowsingURLRequestContextGetter() {}
    131 
    132 net::URLRequestContext*
    133 SafeBrowsingURLRequestContextGetter::GetURLRequestContext() {
    134   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    135   DCHECK(sb_service_->url_request_context_.get());
    136 
    137   return sb_service_->url_request_context_.get();
    138 }
    139 
    140 scoped_refptr<base::SingleThreadTaskRunner>
    141 SafeBrowsingURLRequestContextGetter::GetNetworkTaskRunner() const {
    142   return network_task_runner_;
    143 }
    144 
    145 // static
    146 SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
    147 
    148 // The default SafeBrowsingServiceFactory.  Global, made a singleton so we
    149 // don't leak it.
    150 class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
    151  public:
    152   virtual SafeBrowsingService* CreateSafeBrowsingService() OVERRIDE {
    153     return new SafeBrowsingService();
    154   }
    155 
    156  private:
    157   friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
    158 
    159   SafeBrowsingServiceFactoryImpl() { }
    160 
    161   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
    162 };
    163 
    164 static base::LazyInstance<SafeBrowsingServiceFactoryImpl>::Leaky
    165     g_safe_browsing_service_factory_impl = LAZY_INSTANCE_INITIALIZER;
    166 
    167 // static
    168 base::FilePath SafeBrowsingService::GetCookieFilePathForTesting() {
    169   return CookieFilePath();
    170 }
    171 
    172 // static
    173 base::FilePath SafeBrowsingService::GetBaseFilename() {
    174   base::FilePath path;
    175   bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
    176   DCHECK(result);
    177   return path.Append(chrome::kSafeBrowsingBaseFilename);
    178 }
    179 
    180 
    181 // static
    182 SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
    183   if (!factory_)
    184     factory_ = g_safe_browsing_service_factory_impl.Pointer();
    185   return factory_->CreateSafeBrowsingService();
    186 }
    187 
    188 #if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING)
    189 // static
    190 bool SafeBrowsingService::IsEnabledByFieldTrial() {
    191   const std::string experiment_name =
    192       base::FieldTrialList::FindFullName("SafeBrowsingAndroid");
    193   return experiment_name == "Enabled";
    194 }
    195 #endif
    196 
    197 SafeBrowsingService::SafeBrowsingService()
    198     : protocol_manager_(NULL),
    199       ping_manager_(NULL),
    200       enabled_(false) {
    201 }
    202 
    203 SafeBrowsingService::~SafeBrowsingService() {
    204   // We should have already been shut down. If we're still enabled, then the
    205   // database isn't going to be closed properly, which could lead to corruption.
    206   DCHECK(!enabled_);
    207 }
    208 
    209 void SafeBrowsingService::Initialize() {
    210   startup_metric_utils::ScopedSlowStartupUMA
    211       scoped_timer("Startup.SlowStartupSafeBrowsingServiceInitialize");
    212 
    213   url_request_context_getter_ =
    214       new SafeBrowsingURLRequestContextGetter(this);
    215 
    216   ui_manager_ = CreateUIManager();
    217 
    218   database_manager_ = CreateDatabaseManager();
    219 
    220   BrowserThread::PostTask(
    221       BrowserThread::IO, FROM_HERE,
    222       base::Bind(
    223           &SafeBrowsingService::InitURLRequestContextOnIOThread, this,
    224           make_scoped_refptr(g_browser_process->system_request_context())));
    225 
    226 #if defined(FULL_SAFE_BROWSING)
    227   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    228           switches::kDisableClientSidePhishingDetection)) {
    229     csd_service_.reset(safe_browsing::ClientSideDetectionService::Create(
    230         url_request_context_getter_.get()));
    231   }
    232   download_service_.reset(new safe_browsing::DownloadProtectionService(
    233       this, url_request_context_getter_.get()));
    234 
    235   if (IsIncidentReportingServiceEnabled()) {
    236     incident_service_.reset(new safe_browsing::IncidentReportingService(
    237         this, url_request_context_getter_));
    238   }
    239 #endif
    240 
    241   // Track the safe browsing preference of existing profiles.
    242   // The SafeBrowsingService will be started if any existing profile has the
    243   // preference enabled. It will also listen for updates to the preferences.
    244   ProfileManager* profile_manager = g_browser_process->profile_manager();
    245   if (profile_manager) {
    246     std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
    247     for (size_t i = 0; i < profiles.size(); ++i) {
    248       if (profiles[i]->IsOffTheRecord())
    249         continue;
    250       AddPrefService(profiles[i]->GetPrefs());
    251     }
    252   }
    253 
    254   // Track profile creation and destruction.
    255   prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
    256                        content::NotificationService::AllSources());
    257   prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
    258                        content::NotificationService::AllSources());
    259 }
    260 
    261 void SafeBrowsingService::ShutDown() {
    262   // Deletes the PrefChangeRegistrars, whose dtors also unregister |this| as an
    263   // observer of the preferences.
    264   STLDeleteValues(&prefs_map_);
    265 
    266   // Remove Profile creation/destruction observers.
    267   prefs_registrar_.RemoveAll();
    268 
    269   Stop(true);
    270   // The IO thread is going away, so make sure the ClientSideDetectionService
    271   // dtor executes now since it may call the dtor of URLFetcher which relies
    272   // on it.
    273   csd_service_.reset();
    274   download_service_.reset();
    275   incident_service_.reset();
    276 
    277   url_request_context_getter_ = NULL;
    278   BrowserThread::PostNonNestableTask(
    279       BrowserThread::IO, FROM_HERE,
    280       base::Bind(&SafeBrowsingService::DestroyURLRequestContextOnIOThread,
    281                  this));
    282 }
    283 
    284 // Binhash verification is only enabled for UMA users for now.
    285 bool SafeBrowsingService::DownloadBinHashNeeded() const {
    286   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    287 
    288 #if defined(FULL_SAFE_BROWSING)
    289   return (database_manager_->download_protection_enabled() &&
    290           ui_manager_->CanReportStats()) ||
    291       (download_protection_service() &&
    292        download_protection_service()->enabled());
    293 #else
    294   return false;
    295 #endif
    296 }
    297 
    298 net::URLRequestContextGetter* SafeBrowsingService::url_request_context() {
    299   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    300   return url_request_context_getter_.get();
    301 }
    302 
    303 const scoped_refptr<SafeBrowsingUIManager>&
    304 SafeBrowsingService::ui_manager() const {
    305   return ui_manager_;
    306 }
    307 
    308 const scoped_refptr<SafeBrowsingDatabaseManager>&
    309 SafeBrowsingService::database_manager() const {
    310   return database_manager_;
    311 }
    312 
    313 SafeBrowsingProtocolManager* SafeBrowsingService::protocol_manager() const {
    314   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    315   return protocol_manager_;
    316 }
    317 
    318 SafeBrowsingPingManager* SafeBrowsingService::ping_manager() const {
    319   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    320   return ping_manager_;
    321 }
    322 
    323 scoped_ptr<TrackedPreferenceValidationDelegate>
    324 SafeBrowsingService::CreatePreferenceValidationDelegate(
    325     Profile* profile) const {
    326 #if defined(FULL_SAFE_BROWSING)
    327   if (incident_service_)
    328     return incident_service_->CreatePreferenceValidationDelegate(profile);
    329 #endif
    330   return scoped_ptr<TrackedPreferenceValidationDelegate>();
    331 }
    332 
    333 SafeBrowsingUIManager* SafeBrowsingService::CreateUIManager() {
    334   return new SafeBrowsingUIManager(this);
    335 }
    336 
    337 SafeBrowsingDatabaseManager* SafeBrowsingService::CreateDatabaseManager() {
    338 #if defined(FULL_SAFE_BROWSING)
    339   return new SafeBrowsingDatabaseManager(this);
    340 #else
    341   return NULL;
    342 #endif
    343 }
    344 
    345 void SafeBrowsingService::InitURLRequestContextOnIOThread(
    346     net::URLRequestContextGetter* system_url_request_context_getter) {
    347   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    348   DCHECK(!url_request_context_.get());
    349 
    350   scoped_refptr<net::CookieStore> cookie_store(
    351       content::CreateCookieStore(
    352           content::CookieStoreConfig(
    353               CookieFilePath(),
    354               content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
    355               NULL,
    356               NULL)));
    357 
    358   url_request_context_.reset(new net::URLRequestContext);
    359   // |system_url_request_context_getter| may be NULL during tests.
    360   if (system_url_request_context_getter) {
    361     url_request_context_->CopyFrom(
    362         system_url_request_context_getter->GetURLRequestContext());
    363   }
    364   url_request_context_->set_cookie_store(cookie_store.get());
    365 }
    366 
    367 void SafeBrowsingService::DestroyURLRequestContextOnIOThread() {
    368   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    369 
    370   url_request_context_->AssertNoURLRequests();
    371 
    372   // Need to do the CheckForLeaks on IOThread instead of in ShutDown where
    373   // url_request_context_getter_ is cleared,  since the URLRequestContextGetter
    374   // will PostTask to IOTread to delete itself.
    375   using base::debug::LeakTracker;
    376   LeakTracker<SafeBrowsingURLRequestContextGetter>::CheckForLeaks();
    377 
    378   url_request_context_.reset();
    379 }
    380 
    381 SafeBrowsingProtocolConfig SafeBrowsingService::GetProtocolConfig() const {
    382   SafeBrowsingProtocolConfig config;
    383   // On Windows, get the safe browsing client name from the browser
    384   // distribution classes in installer util. These classes don't yet have
    385   // an analog on non-Windows builds so just keep the name specified here.
    386 #if defined(OS_WIN)
    387   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    388   config.client_name = dist->GetSafeBrowsingName();
    389 #else
    390 #if defined(GOOGLE_CHROME_BUILD)
    391   config.client_name = "googlechrome";
    392 #else
    393   config.client_name = "chromium";
    394 #endif
    395 
    396   // Mark client string to allow server to differentiate mobile.
    397 #if defined(OS_ANDROID)
    398   config.client_name.append("-a");
    399 #elif defined(OS_IOS)
    400   config.client_name.append("-i");
    401 #endif
    402 
    403 #endif  // defined(OS_WIN)
    404   CommandLine* cmdline = CommandLine::ForCurrentProcess();
    405   config.disable_auto_update =
    406       cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
    407       cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
    408   config.url_prefix = kSbDefaultURLPrefix;
    409   config.backup_connect_error_url_prefix = kSbBackupConnectErrorURLPrefix;
    410   config.backup_http_error_url_prefix = kSbBackupHttpErrorURLPrefix;
    411   config.backup_network_error_url_prefix = kSbBackupNetworkErrorURLPrefix;
    412 
    413   return config;
    414 }
    415 
    416 void SafeBrowsingService::StartOnIOThread(
    417     net::URLRequestContextGetter* url_request_context_getter) {
    418   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    419   if (enabled_)
    420     return;
    421   enabled_ = true;
    422 
    423   SafeBrowsingProtocolConfig config = GetProtocolConfig();
    424 
    425 #if defined(FULL_SAFE_BROWSING)
    426   DCHECK(database_manager_.get());
    427   database_manager_->StartOnIOThread();
    428 
    429   DCHECK(!protocol_manager_);
    430   protocol_manager_ = SafeBrowsingProtocolManager::Create(
    431       database_manager_.get(), url_request_context_getter, config);
    432   protocol_manager_->Initialize();
    433 #endif
    434 
    435   DCHECK(!ping_manager_);
    436   ping_manager_ = SafeBrowsingPingManager::Create(
    437       url_request_context_getter, config);
    438 }
    439 
    440 void SafeBrowsingService::StopOnIOThread(bool shutdown) {
    441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    442 
    443 #if defined(FULL_SAFE_BROWSING)
    444   database_manager_->StopOnIOThread(shutdown);
    445 #endif
    446   ui_manager_->StopOnIOThread(shutdown);
    447 
    448   if (enabled_) {
    449     enabled_ = false;
    450 
    451 #if defined(FULL_SAFE_BROWSING)
    452     // This cancels all in-flight GetHash requests. Note that database_manager_
    453     // relies on the protocol_manager_ so if the latter is destroyed, the
    454     // former must be stopped.
    455     delete protocol_manager_;
    456     protocol_manager_ = NULL;
    457 #endif
    458     delete ping_manager_;
    459     ping_manager_ = NULL;
    460   }
    461 }
    462 
    463 void SafeBrowsingService::Start() {
    464   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    465 
    466   BrowserThread::PostTask(
    467       BrowserThread::IO, FROM_HERE,
    468       base::Bind(&SafeBrowsingService::StartOnIOThread, this,
    469                  url_request_context_getter_));
    470 }
    471 
    472 void SafeBrowsingService::Stop(bool shutdown) {
    473   BrowserThread::PostTask(
    474       BrowserThread::IO, FROM_HERE,
    475       base::Bind(&SafeBrowsingService::StopOnIOThread, this, shutdown));
    476 }
    477 
    478 void SafeBrowsingService::Observe(int type,
    479                                   const content::NotificationSource& source,
    480                                   const content::NotificationDetails& details) {
    481   switch (type) {
    482     case chrome::NOTIFICATION_PROFILE_CREATED: {
    483       DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    484       Profile* profile = content::Source<Profile>(source).ptr();
    485       if (!profile->IsOffTheRecord())
    486         AddPrefService(profile->GetPrefs());
    487       break;
    488     }
    489     case chrome::NOTIFICATION_PROFILE_DESTROYED: {
    490       DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    491       Profile* profile = content::Source<Profile>(source).ptr();
    492       if (!profile->IsOffTheRecord())
    493         RemovePrefService(profile->GetPrefs());
    494       break;
    495     }
    496     default:
    497       NOTREACHED();
    498   }
    499 }
    500 
    501 void SafeBrowsingService::AddPrefService(PrefService* pref_service) {
    502   DCHECK(prefs_map_.find(pref_service) == prefs_map_.end());
    503   PrefChangeRegistrar* registrar = new PrefChangeRegistrar();
    504   registrar->Init(pref_service);
    505   registrar->Add(prefs::kSafeBrowsingEnabled,
    506                  base::Bind(&SafeBrowsingService::RefreshState,
    507                             base::Unretained(this)));
    508   prefs_map_[pref_service] = registrar;
    509   RefreshState();
    510 }
    511 
    512 void SafeBrowsingService::RemovePrefService(PrefService* pref_service) {
    513   if (prefs_map_.find(pref_service) != prefs_map_.end()) {
    514     delete prefs_map_[pref_service];
    515     prefs_map_.erase(pref_service);
    516     RefreshState();
    517   } else {
    518     NOTREACHED();
    519   }
    520 }
    521 
    522 void SafeBrowsingService::RefreshState() {
    523   // Check if any profile requires the service to be active.
    524   bool enable = false;
    525   std::map<PrefService*, PrefChangeRegistrar*>::iterator iter;
    526   for (iter = prefs_map_.begin(); iter != prefs_map_.end(); ++iter) {
    527     if (iter->first->GetBoolean(prefs::kSafeBrowsingEnabled)) {
    528       enable = true;
    529       break;
    530     }
    531   }
    532 
    533   if (enable)
    534     Start();
    535   else
    536     Stop(false);
    537 
    538 #if defined(FULL_SAFE_BROWSING)
    539   if (csd_service_)
    540     csd_service_->SetEnabledAndRefreshState(enable);
    541   if (download_service_)
    542     download_service_->SetEnabled(enable);
    543 #endif
    544 }
    545