| OLD | NEW | 
|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/safe_browsing/client_side_detection_service.h" | 5 #include "chrome/browser/safe_browsing/client_side_detection_service.h" | 
| 6 | 6 | 
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" | 
| 8 #include "base/logging.h" | 8 #include "base/logging.h" | 
| 9 #include "base/time.h" | 9 #include "base/time.h" | 
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" | 
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" | 
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" | 
|  | 13 #include "base/string_util.h" | 
| 13 #include "base/stl_util.h" | 14 #include "base/stl_util.h" | 
| 14 #include "base/task.h" | 15 #include "base/task.h" | 
| 15 #include "base/time.h" | 16 #include "base/time.h" | 
|  | 17 #include "chrome/browser/browser_process.h" | 
|  | 18 #include "chrome/browser/safe_browsing/browser_features.h" | 
|  | 19 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 
| 16 #include "chrome/common/net/http_return.h" | 20 #include "chrome/common/net/http_return.h" | 
| 17 #include "chrome/common/safe_browsing/client_model.pb.h" | 21 #include "chrome/common/safe_browsing/client_model.pb.h" | 
| 18 #include "chrome/common/safe_browsing/csd.pb.h" | 22 #include "chrome/common/safe_browsing/csd.pb.h" | 
| 19 #include "chrome/common/safe_browsing/safebrowsing_messages.h" | 23 #include "chrome/common/safe_browsing/safebrowsing_messages.h" | 
|  | 24 #include "chrome/renderer/safe_browsing/features.h" | 
| 20 #include "content/browser/browser_thread.h" | 25 #include "content/browser/browser_thread.h" | 
| 21 #include "content/browser/renderer_host/render_process_host.h" | 26 #include "content/browser/renderer_host/render_process_host.h" | 
| 22 #include "content/common/notification_service.h" | 27 #include "content/common/notification_service.h" | 
| 23 #include "content/common/url_fetcher.h" | 28 #include "content/common/url_fetcher.h" | 
| 24 #include "crypto/sha2.h" | 29 #include "crypto/sha2.h" | 
| 25 #include "googleurl/src/gurl.h" | 30 #include "googleurl/src/gurl.h" | 
| 26 #include "net/base/load_flags.h" | 31 #include "net/base/load_flags.h" | 
| 27 #include "net/http/http_response_headers.h" | 32 #include "net/http/http_response_headers.h" | 
| 28 #include "net/url_request/url_request_context_getter.h" | 33 #include "net/url_request/url_request_context_getter.h" | 
| 29 #include "net/url_request/url_request_status.h" | 34 #include "net/url_request/url_request_status.h" | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 57   GURL phishing_url; | 62   GURL phishing_url; | 
| 58 }; | 63 }; | 
| 59 | 64 | 
| 60 ClientSideDetectionService::CacheState::CacheState(bool phish, base::Time time) | 65 ClientSideDetectionService::CacheState::CacheState(bool phish, base::Time time) | 
| 61     : is_phishing(phish), | 66     : is_phishing(phish), | 
| 62       timestamp(time) {} | 67       timestamp(time) {} | 
| 63 | 68 | 
| 64 ClientSideDetectionService::ClientSideDetectionService( | 69 ClientSideDetectionService::ClientSideDetectionService( | 
| 65     net::URLRequestContextGetter* request_context_getter) | 70     net::URLRequestContextGetter* request_context_getter) | 
| 66     : enabled_(false), | 71     : enabled_(false), | 
|  | 72       sb_service_(g_browser_process->safe_browsing_service()), | 
| 67       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), | 73       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), | 
| 68       request_context_getter_(request_context_getter) { | 74       request_context_getter_(request_context_getter) { | 
|  | 75   InitializeAllowedFeatures(); | 
| 69   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 76   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 
| 70                  NotificationService::AllSources()); | 77                  NotificationService::AllSources()); | 
| 71 } | 78 } | 
| 72 | 79 | 
| 73 ClientSideDetectionService::~ClientSideDetectionService() { | 80 ClientSideDetectionService::~ClientSideDetectionService() { | 
| 74   method_factory_.RevokeAll(); | 81   method_factory_.RevokeAll(); | 
| 75   STLDeleteContainerPairPointers(client_phishing_reports_.begin(), | 82   STLDeleteContainerPairPointers(client_phishing_reports_.begin(), | 
| 76                                  client_phishing_reports_.end()); | 83                                  client_phishing_reports_.end()); | 
| 77   client_phishing_reports_.clear(); | 84   client_phishing_reports_.clear(); | 
| 78 } | 85 } | 
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 259     // the model's age. | 266     // the model's age. | 
| 260     *model_max_age_ += base::TimeDelta::FromMinutes(1); | 267     *model_max_age_ += base::TimeDelta::FromMinutes(1); | 
| 261     delay_ms = model_max_age_->InMilliseconds(); | 268     delay_ms = model_max_age_->InMilliseconds(); | 
| 262   } | 269   } | 
| 263   model_max_age_.reset(); | 270   model_max_age_.reset(); | 
| 264 | 271 | 
| 265   // Schedule the next model reload. | 272   // Schedule the next model reload. | 
| 266   ScheduleFetchModel(delay_ms); | 273   ScheduleFetchModel(delay_ms); | 
| 267 } | 274 } | 
| 268 | 275 | 
|  | 276 void ClientSideDetectionService::SanitizeRequestForPingback( | 
|  | 277     const ClientPhishingRequest& full_request, | 
|  | 278     ClientPhishingRequest* sanitized_request) { | 
|  | 279   DCHECK(full_request.IsInitialized()); | 
|  | 280   sanitized_request->Clear(); | 
|  | 281   if (full_request.has_suffix_prefix_hash()) { | 
|  | 282     sanitized_request->set_suffix_prefix_hash( | 
|  | 283         full_request.suffix_prefix_hash()); | 
|  | 284   } | 
|  | 285   sanitized_request->set_client_score(full_request.client_score()); | 
|  | 286   if (full_request.has_is_phishing()) { | 
|  | 287     sanitized_request->set_is_phishing(full_request.is_phishing()); | 
|  | 288   } | 
|  | 289 | 
|  | 290   for (int i = 0; i < full_request.feature_map_size(); ++i) { | 
|  | 291     const ClientPhishingRequest_Feature& feature = full_request.feature_map(i); | 
|  | 292     if (allowed_features_.find(feature.name()) != allowed_features_.end()) { | 
|  | 293       sanitized_request->add_feature_map()->CopyFrom(feature); | 
|  | 294     } | 
|  | 295   } | 
|  | 296 | 
|  | 297   if (full_request.has_model_version()) { | 
|  | 298     sanitized_request->set_model_version(full_request.model_version()); | 
|  | 299   } | 
|  | 300 | 
|  | 301   for (int i = 0; i < full_request.non_model_feature_map_size(); ++i) { | 
|  | 302     const ClientPhishingRequest_Feature& feature = | 
|  | 303         full_request.non_model_feature_map(i); | 
|  | 304     if (allowed_features_.find(feature.name()) != allowed_features_.end()) { | 
|  | 305       sanitized_request->add_non_model_feature_map()->CopyFrom(feature); | 
|  | 306     } | 
|  | 307   } | 
|  | 308 } | 
|  | 309 | 
| 269 void ClientSideDetectionService::StartClientReportPhishingRequest( | 310 void ClientSideDetectionService::StartClientReportPhishingRequest( | 
| 270     ClientPhishingRequest* verdict, | 311     ClientPhishingRequest* verdict, | 
| 271     ClientReportPhishingRequestCallback* callback) { | 312     ClientReportPhishingRequestCallback* callback) { | 
| 272   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 313   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| 273   scoped_ptr<ClientPhishingRequest> request(verdict); | 314   scoped_ptr<ClientPhishingRequest> request(verdict); | 
| 274   scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); | 315   scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); | 
| 275 | 316 | 
| 276   if (!enabled_) { | 317   if (!enabled_) { | 
| 277     if (cb.get()) | 318     if (cb.get()) | 
| 278       cb->Run(GURL(request->url()), false); | 319       cb->Run(GURL(request->url()), false); | 
| 279     return; | 320     return; | 
| 280   } | 321   } | 
| 281 | 322 | 
|  | 323   // Create the version of the request proto that we'll send over the network. | 
|  | 324   ClientPhishingRequest request_to_send; | 
|  | 325   if (sb_service_ && sb_service_->CanReportStats()) { | 
|  | 326     request_to_send.CopyFrom(*request); | 
|  | 327   } else { | 
|  | 328     SanitizeRequestForPingback(*request, &request_to_send); | 
|  | 329   } | 
|  | 330 | 
| 282   std::string request_data; | 331   std::string request_data; | 
| 283   if (!request->SerializeToString(&request_data)) { | 332   if (!request_to_send.SerializeToString(&request_data)) { | 
| 284     UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); | 333     UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); | 
| 285     VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; | 334     VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; | 
| 286     if (cb.get()) { | 335     if (cb.get()) { | 
| 287       cb->Run(GURL(request->url()), false); | 336       cb->Run(GURL(request->url()), false); | 
| 288     } | 337     } | 
| 289     return; | 338     return; | 
| 290   } | 339   } | 
| 291 | 340 | 
| 292   URLFetcher* fetcher = URLFetcher::Create(0 /* ID is not used */, | 341   URLFetcher* fetcher = URLFetcher::Create(0 /* ID is not used */, | 
| 293                                            GURL(kClientReportPhishingUrl), | 342                                            GURL(kClientReportPhishingUrl), | 
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 463       private_networks_.push_back(std::make_pair(ip_number, prefix_length)); | 512       private_networks_.push_back(std::make_pair(ip_number, prefix_length)); | 
| 464     } else { | 513     } else { | 
| 465       DLOG(FATAL) << "Unable to parse IP address range: " | 514       DLOG(FATAL) << "Unable to parse IP address range: " | 
| 466                   << kPrivateNetworks[i]; | 515                   << kPrivateNetworks[i]; | 
| 467       return false; | 516       return false; | 
| 468     } | 517     } | 
| 469   } | 518   } | 
| 470   return true; | 519   return true; | 
| 471 } | 520 } | 
| 472 | 521 | 
|  | 522 void ClientSideDetectionService::InitializeAllowedFeatures() { | 
|  | 523   static const char* const kAllowedFeatures[] = { | 
|  | 524     // Renderer (model) features. | 
|  | 525     features::kUrlHostIsIpAddress, | 
|  | 526     features::kUrlNumOtherHostTokensGTOne, | 
|  | 527     features::kUrlNumOtherHostTokensGTThree, | 
|  | 528     features::kPageHasForms, | 
|  | 529     features::kPageActionOtherDomainFreq, | 
|  | 530     features::kPageHasTextInputs, | 
|  | 531     features::kPageHasPswdInputs, | 
|  | 532     features::kPageHasRadioInputs, | 
|  | 533     features::kPageHasCheckInputs, | 
|  | 534     features::kPageExternalLinksFreq, | 
|  | 535     features::kPageSecureLinksFreq, | 
|  | 536     features::kPageNumScriptTagsGTOne, | 
|  | 537     features::kPageNumScriptTagsGTSix, | 
|  | 538     features::kPageImgOtherDomainFreq, | 
|  | 539     // Browser (non-model) features. | 
|  | 540     features::kUrlHistoryVisitCount, | 
|  | 541     features::kUrlHistoryTypedCount, | 
|  | 542     features::kUrlHistoryLinkCount, | 
|  | 543     features::kUrlHistoryVisitCountMoreThan24hAgo, | 
|  | 544     features::kHttpHostVisitCount, | 
|  | 545     features::kHttpsHostVisitCount, | 
|  | 546     features::kFirstHttpHostVisitMoreThan24hAgo, | 
|  | 547     features::kFirstHttpsHostVisitMoreThan24hAgo, | 
|  | 548     features::kHasSSLReferrer, | 
|  | 549     features::kPageTransitionType, | 
|  | 550     features::kIsFirstNavigation, | 
|  | 551     features::kSafeBrowsingIsSubresource, | 
|  | 552     features::kSafeBrowsingThreatType, | 
|  | 553   }; | 
|  | 554 | 
|  | 555   for (size_t i = 0; i < arraysize(kAllowedFeatures); ++i) { | 
|  | 556     allowed_features_.insert(kAllowedFeatures[i]); | 
|  | 557   } | 
|  | 558 } | 
|  | 559 | 
| 473 // static | 560 // static | 
| 474 void ClientSideDetectionService::SetBadSubnets(const ClientSideModel& model, | 561 void ClientSideDetectionService::SetBadSubnets(const ClientSideModel& model, | 
| 475                                                BadSubnetMap* bad_subnets) { | 562                                                BadSubnetMap* bad_subnets) { | 
| 476   bad_subnets->clear(); | 563   bad_subnets->clear(); | 
| 477   for (int i = 0; i < model.bad_subnet_size(); ++i) { | 564   for (int i = 0; i < model.bad_subnet_size(); ++i) { | 
| 478     int size = model.bad_subnet(i).size(); | 565     int size = model.bad_subnet(i).size(); | 
| 479     if (size < 0 || size > static_cast<int>(net::kIPv6AddressSize) * 8) { | 566     if (size < 0 || size > static_cast<int>(net::kIPv6AddressSize) * 8) { | 
| 480       DLOG(ERROR) << "Invalid bad subnet size: " << size; | 567       DLOG(ERROR) << "Invalid bad subnet size: " << size; | 
| 481       continue; | 568       continue; | 
| 482     } | 569     } | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 515     } | 602     } | 
| 516   } | 603   } | 
| 517   for (int i = 0; i < model.page_word_size(); ++i) { | 604   for (int i = 0; i < model.page_word_size(); ++i) { | 
| 518     if (model.page_word(i) < 0 || model.page_word(i) > max_index) { | 605     if (model.page_word(i) < 0 || model.page_word(i) > max_index) { | 
| 519       return false; | 606       return false; | 
| 520     } | 607     } | 
| 521   } | 608   } | 
| 522   return true; | 609   return true; | 
| 523 } | 610 } | 
| 524 }  // namespace safe_browsing | 611 }  // namespace safe_browsing | 
| OLD | NEW | 
|---|