| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/protocol_manager.h" | 5 #include "chrome/browser/safe_browsing/protocol_manager.h" |
| 6 | 6 |
| 7 #ifndef NDEBUG | 7 #ifndef NDEBUG |
| 8 #include "base/base64.h" | 8 #include "base/base64.h" |
| 9 #endif | 9 #endif |
| 10 #include "base/environment.h" | 10 #include "base/environment.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 | 41 |
| 42 // SafeBrowsingProtocolManager implementation ---------------------------------- | 42 // SafeBrowsingProtocolManager implementation ---------------------------------- |
| 43 | 43 |
| 44 SafeBrowsingProtocolManager::SafeBrowsingProtocolManager( | 44 SafeBrowsingProtocolManager::SafeBrowsingProtocolManager( |
| 45 SafeBrowsingService* sb_service, | 45 SafeBrowsingService* sb_service, |
| 46 const std::string& client_name, | 46 const std::string& client_name, |
| 47 const std::string& client_key, | 47 const std::string& client_key, |
| 48 const std::string& wrapped_key, | 48 const std::string& wrapped_key, |
| 49 URLRequestContextGetter* request_context_getter, | 49 URLRequestContextGetter* request_context_getter, |
| 50 const std::string& info_url_prefix, | 50 const std::string& http_url_prefix, |
| 51 const std::string& mackey_url_prefix, | 51 const std::string& https_url_prefix, |
| 52 bool disable_auto_update) | 52 bool disable_auto_update) |
| 53 : sb_service_(sb_service), | 53 : sb_service_(sb_service), |
| 54 request_type_(NO_REQUEST), | 54 request_type_(NO_REQUEST), |
| 55 update_error_count_(0), | 55 update_error_count_(0), |
| 56 gethash_error_count_(0), | 56 gethash_error_count_(0), |
| 57 update_back_off_mult_(1), | 57 update_back_off_mult_(1), |
| 58 gethash_back_off_mult_(1), | 58 gethash_back_off_mult_(1), |
| 59 next_update_sec_(-1), | 59 next_update_sec_(-1), |
| 60 update_state_(FIRST_REQUEST), | 60 update_state_(FIRST_REQUEST), |
| 61 initial_request_(true), | 61 initial_request_(true), |
| 62 chunk_pending_to_write_(false), | 62 chunk_pending_to_write_(false), |
| 63 client_key_(client_key), | 63 client_key_(client_key), |
| 64 wrapped_key_(wrapped_key), | 64 wrapped_key_(wrapped_key), |
| 65 update_size_(0), | 65 update_size_(0), |
| 66 client_name_(client_name), | 66 client_name_(client_name), |
| 67 request_context_getter_(request_context_getter), | 67 request_context_getter_(request_context_getter), |
| 68 info_url_prefix_(info_url_prefix), | 68 http_url_prefix_(http_url_prefix), |
| 69 mackey_url_prefix_(mackey_url_prefix), | 69 https_url_prefix_(https_url_prefix), |
| 70 disable_auto_update_(disable_auto_update) { | 70 disable_auto_update_(disable_auto_update) { |
| 71 DCHECK(!info_url_prefix_.empty() && !mackey_url_prefix_.empty()); | 71 DCHECK(!http_url_prefix_.empty() && !https_url_prefix_.empty()); |
| 72 | 72 |
| 73 // Set the backoff multiplier fuzz to a random value between 0 and 1. | 73 // Set the backoff multiplier fuzz to a random value between 0 and 1. |
| 74 back_off_fuzz_ = static_cast<float>(base::RandDouble()); | 74 back_off_fuzz_ = static_cast<float>(base::RandDouble()); |
| 75 // The first update must happen between 1-5 minutes of start up. | 75 // The first update must happen between 1-5 minutes of start up. |
| 76 next_update_sec_ = base::RandInt(60, kSbTimerStartIntervalSec); | 76 next_update_sec_ = base::RandInt(60, kSbTimerStartIntervalSec); |
| 77 | 77 |
| 78 chrome::VersionInfo version_info; | 78 chrome::VersionInfo version_info; |
| 79 if (!version_info.is_valid() || version_info.Version().empty()) | 79 if (!version_info.is_valid() || version_info.Version().empty()) |
| 80 version_ = "0.1"; | 80 version_ = "0.1"; |
| 81 else | 81 else |
| 82 version_ = version_info.Version(); | 82 version_ = version_info.Version(); |
| 83 } | 83 } |
| 84 | 84 |
| 85 SafeBrowsingProtocolManager::~SafeBrowsingProtocolManager() { | 85 SafeBrowsingProtocolManager::~SafeBrowsingProtocolManager() { |
| 86 // Delete in-progress SafeBrowsing requests. | 86 // Delete in-progress SafeBrowsing requests. |
| 87 STLDeleteContainerPairFirstPointers(hash_requests_.begin(), | 87 STLDeleteContainerPairFirstPointers(hash_requests_.begin(), |
| 88 hash_requests_.end()); | 88 hash_requests_.end()); |
| 89 hash_requests_.clear(); | 89 hash_requests_.clear(); |
| 90 | 90 |
| 91 // Delete in-progress safebrowsing reports. | 91 // Delete in-progress safebrowsing reports (hits and details). |
| 92 STLDeleteContainerPointers(safebrowsing_reports_.begin(), | 92 STLDeleteContainerPointers(safebrowsing_reports_.begin(), |
| 93 safebrowsing_reports_.end()); | 93 safebrowsing_reports_.end()); |
| 94 safebrowsing_reports_.clear(); | 94 safebrowsing_reports_.clear(); |
| 95 } | 95 } |
| 96 | 96 |
| 97 // Public API used by the SafeBrowsingService ---------------------------------- | 97 // Public API used by the SafeBrowsingService ---------------------------------- |
| 98 | 98 |
| 99 // We can only have one update or chunk request outstanding, but there may be | 99 // We can only have one update or chunk request outstanding, but there may be |
| 100 // multiple GetHash requests pending since we don't want to serialize them and | 100 // multiple GetHash requests pending since we don't want to serialize them and |
| 101 // slow down the user. | 101 // slow down the user. |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 chunk_pending_to_write_ = false; | 581 chunk_pending_to_write_ = false; |
| 582 | 582 |
| 583 if (chunk_request_urls_.empty()) { | 583 if (chunk_request_urls_.empty()) { |
| 584 UMA_HISTOGRAM_LONG_TIMES("SB2.Update", Time::Now() - last_update_); | 584 UMA_HISTOGRAM_LONG_TIMES("SB2.Update", Time::Now() - last_update_); |
| 585 UpdateFinished(true); | 585 UpdateFinished(true); |
| 586 } else { | 586 } else { |
| 587 IssueChunkRequest(); | 587 IssueChunkRequest(); |
| 588 } | 588 } |
| 589 } | 589 } |
| 590 | 590 |
| 591 // Sends a SafeBrowsing "hit" for UMA users. |
| 591 void SafeBrowsingProtocolManager::ReportSafeBrowsingHit( | 592 void SafeBrowsingProtocolManager::ReportSafeBrowsingHit( |
| 592 const GURL& malicious_url, | 593 const GURL& malicious_url, |
| 593 const GURL& page_url, | 594 const GURL& page_url, |
| 594 const GURL& referrer_url, | 595 const GURL& referrer_url, |
| 595 bool is_subresource, | 596 bool is_subresource, |
| 596 SafeBrowsingService::UrlCheckResult threat_type) { | 597 SafeBrowsingService::UrlCheckResult threat_type) { |
| 597 GURL report_url = SafeBrowsingReportUrl(malicious_url, page_url, | 598 GURL report_url = SafeBrowsingHitUrl(malicious_url, page_url, |
| 598 referrer_url, is_subresource, | 599 referrer_url, is_subresource, |
| 599 threat_type); | 600 threat_type); |
| 600 URLFetcher* report = new URLFetcher(report_url, URLFetcher::GET, this); | 601 URLFetcher* report = new URLFetcher(report_url, URLFetcher::GET, this); |
| 601 report->set_load_flags(net::LOAD_DISABLE_CACHE); | 602 report->set_load_flags(net::LOAD_DISABLE_CACHE); |
| 602 report->set_request_context(request_context_getter_); | 603 report->set_request_context(request_context_getter_); |
| 603 report->Start(); | 604 report->Start(); |
| 604 safebrowsing_reports_.insert(report); | 605 safebrowsing_reports_.insert(report); |
| 605 } | 606 } |
| 606 | 607 |
| 608 // Sends malware details for users who opt-in. |
| 609 void SafeBrowsingProtocolManager::ReportMalwareDetails( |
| 610 const std::string& report) { |
| 611 GURL report_url = MalwareDetailsUrl(); |
| 612 URLFetcher* fetcher = new URLFetcher(report_url, URLFetcher::POST, this); |
| 613 fetcher->set_load_flags(net::LOAD_DISABLE_CACHE); |
| 614 fetcher->set_request_context(request_context_getter_); |
| 615 fetcher->set_upload_data("application/octet-stream", report); |
| 616 // Don't try too hard to send reports on failures. |
| 617 fetcher->set_automatically_retry_on_5xx(false); |
| 618 fetcher->Start(); |
| 619 safebrowsing_reports_.insert(fetcher); |
| 620 } |
| 621 |
| 622 |
| 607 // static | 623 // static |
| 608 std::string SafeBrowsingProtocolManager::FormatList( | 624 std::string SafeBrowsingProtocolManager::FormatList( |
| 609 const SBListChunkRanges& list, bool use_mac) { | 625 const SBListChunkRanges& list, bool use_mac) { |
| 610 std::string formatted_results; | 626 std::string formatted_results; |
| 611 formatted_results.append(list.name); | 627 formatted_results.append(list.name); |
| 612 formatted_results.append(";"); | 628 formatted_results.append(";"); |
| 613 if (!list.adds.empty()) { | 629 if (!list.adds.empty()) { |
| 614 formatted_results.append("a:" + list.adds); | 630 formatted_results.append("a:" + list.adds); |
| 615 if (!list.subs.empty() || use_mac) | 631 if (!list.subs.empty() || use_mac) |
| 616 formatted_results.append(":"); | 632 formatted_results.append(":"); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 client_name.c_str(), version.c_str()); | 671 client_name.c_str(), version.c_str()); |
| 656 if (!additional_query.empty()) { | 672 if (!additional_query.empty()) { |
| 657 DCHECK(url.find("?") != std::string::npos); | 673 DCHECK(url.find("?") != std::string::npos); |
| 658 url.append("&"); | 674 url.append("&"); |
| 659 url.append(additional_query); | 675 url.append(additional_query); |
| 660 } | 676 } |
| 661 return url; | 677 return url; |
| 662 } | 678 } |
| 663 | 679 |
| 664 GURL SafeBrowsingProtocolManager::UpdateUrl(bool use_mac) const { | 680 GURL SafeBrowsingProtocolManager::UpdateUrl(bool use_mac) const { |
| 665 std::string url = ComposeUrl(info_url_prefix_, "downloads", client_name_, | 681 std::string url = ComposeUrl(http_url_prefix_, "downloads", client_name_, |
| 666 version_, additional_query_); | 682 version_, additional_query_); |
| 667 if (use_mac) { | 683 if (use_mac) { |
| 668 url.append("&wrkey="); | 684 url.append("&wrkey="); |
| 669 url.append(wrapped_key_); | 685 url.append(wrapped_key_); |
| 670 } | 686 } |
| 671 return GURL(url); | 687 return GURL(url); |
| 672 } | 688 } |
| 673 | 689 |
| 674 GURL SafeBrowsingProtocolManager::GetHashUrl(bool use_mac) const { | 690 GURL SafeBrowsingProtocolManager::GetHashUrl(bool use_mac) const { |
| 675 std::string url= ComposeUrl(info_url_prefix_, "gethash", client_name_, | 691 std::string url= ComposeUrl(http_url_prefix_, "gethash", client_name_, |
| 676 version_, additional_query_); | 692 version_, additional_query_); |
| 677 if (use_mac) { | 693 if (use_mac) { |
| 678 url.append("&wrkey="); | 694 url.append("&wrkey="); |
| 679 url.append(wrapped_key_); | 695 url.append(wrapped_key_); |
| 680 } | 696 } |
| 681 return GURL(url); | 697 return GURL(url); |
| 682 } | 698 } |
| 683 | 699 |
| 684 GURL SafeBrowsingProtocolManager::MacKeyUrl() const { | 700 GURL SafeBrowsingProtocolManager::MacKeyUrl() const { |
| 685 return GURL(ComposeUrl(mackey_url_prefix_, "newkey", client_name_, version_, | 701 return GURL(ComposeUrl(https_url_prefix_, "newkey", client_name_, version_, |
| 686 additional_query_)); | 702 additional_query_)); |
| 687 } | 703 } |
| 688 | 704 |
| 689 GURL SafeBrowsingProtocolManager::SafeBrowsingReportUrl( | 705 GURL SafeBrowsingProtocolManager::SafeBrowsingHitUrl( |
| 690 const GURL& malicious_url, const GURL& page_url, | 706 const GURL& malicious_url, const GURL& page_url, |
| 691 const GURL& referrer_url, bool is_subresource, | 707 const GURL& referrer_url, bool is_subresource, |
| 692 SafeBrowsingService::UrlCheckResult threat_type) const { | 708 SafeBrowsingService::UrlCheckResult threat_type) const { |
| 693 DCHECK(threat_type == SafeBrowsingService::URL_MALWARE || | 709 DCHECK(threat_type == SafeBrowsingService::URL_MALWARE || |
| 694 threat_type == SafeBrowsingService::URL_PHISHING); | 710 threat_type == SafeBrowsingService::URL_PHISHING); |
| 695 std::string url = ComposeUrl(info_url_prefix_, "report", client_name_, | 711 // The malware and phishing hits go over HTTP. |
| 712 std::string url = ComposeUrl(http_url_prefix_, "report", client_name_, |
| 696 version_, additional_query_); | 713 version_, additional_query_); |
| 697 return GURL(StringPrintf("%s&evts=%s&evtd=%s&evtr=%s&evhr=%s&evtb=%d", | 714 return GURL(StringPrintf("%s&evts=%s&evtd=%s&evtr=%s&evhr=%s&evtb=%d", |
| 698 url.c_str(), | 715 url.c_str(), |
| 699 (threat_type == SafeBrowsingService::URL_MALWARE) ? | 716 (threat_type == SafeBrowsingService::URL_MALWARE) ? |
| 700 "malblhit" : "phishblhit", | 717 "malblhit" : "phishblhit", |
| 701 EscapeQueryParamValue(malicious_url.spec(), true).c_str(), | 718 EscapeQueryParamValue(malicious_url.spec(), true).c_str(), |
| 702 EscapeQueryParamValue(page_url.spec(), true).c_str(), | 719 EscapeQueryParamValue(page_url.spec(), true).c_str(), |
| 703 EscapeQueryParamValue(referrer_url.spec(), true).c_str(), | 720 EscapeQueryParamValue(referrer_url.spec(), true).c_str(), |
| 704 is_subresource)); | 721 is_subresource)); |
| 705 } | 722 } |
| 706 | 723 |
| 724 GURL SafeBrowsingProtocolManager::MalwareDetailsUrl() const { |
| 725 // The malware details go over HTTPS. |
| 726 std::string url = StringPrintf( |
| 727 "%s/clientreport/malware?client=%s&appver=%s&pver=1.0", |
| 728 https_url_prefix_.c_str(), |
| 729 client_name_.c_str(), |
| 730 version_.c_str()); |
| 731 return GURL(url); |
| 732 } |
| 733 |
| 707 GURL SafeBrowsingProtocolManager::NextChunkUrl(const std::string& url) const { | 734 GURL SafeBrowsingProtocolManager::NextChunkUrl(const std::string& url) const { |
| 708 std::string next_url; | 735 std::string next_url; |
| 709 if (!StartsWithASCII(url, "http://", false) && | 736 if (!StartsWithASCII(url, "http://", false) && |
| 710 !StartsWithASCII(url, "https://", false)) { | 737 !StartsWithASCII(url, "https://", false)) { |
| 711 next_url.append("http://"); | 738 next_url.append("http://"); |
| 712 next_url.append(url); | 739 next_url.append(url); |
| 713 } else { | 740 } else { |
| 714 next_url = url; | 741 next_url = url; |
| 715 } | 742 } |
| 716 if (!additional_query_.empty()) { | 743 if (!additional_query_.empty()) { |
| 717 if (next_url.find("?") != std::string::npos) { | 744 if (next_url.find("?") != std::string::npos) { |
| 718 next_url.append("&"); | 745 next_url.append("&"); |
| 719 } else { | 746 } else { |
| 720 next_url.append("?"); | 747 next_url.append("?"); |
| 721 } | 748 } |
| 722 next_url.append(additional_query_); | 749 next_url.append(additional_query_); |
| 723 } | 750 } |
| 724 return GURL(next_url); | 751 return GURL(next_url); |
| 725 } | 752 } |
| OLD | NEW |