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