Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(344)

Side by Side Diff: chrome/browser/safe_browsing/download_protection_service.cc

Issue 10382113: Add SafeBrowsing support for checking downloaded zip files that contain executables. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Matt's review comments Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/download_protection_service.h" 5 #include "chrome/browser/safe_browsing/download_protection_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/memory/weak_ptr.h" 11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop_helpers.h" 12 #include "base/message_loop_helpers.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
16 #include "base/string_util.h" 16 #include "base/string_util.h"
17 #include "base/stringprintf.h" 17 #include "base/stringprintf.h"
18 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/time.h" 19 #include "base/time.h"
20 #include "chrome/browser/safe_browsing/safe_browsing_service.h" 20 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
21 #include "chrome/browser/safe_browsing/signature_util.h" 21 #include "chrome/browser/safe_browsing/signature_util.h"
22 #include "chrome/browser/ui/browser_list.h" 22 #include "chrome/browser/ui/browser_list.h"
23 #include "chrome/common/safe_browsing/csd.pb.h" 23 #include "chrome/common/safe_browsing/csd.pb.h"
24 #include "chrome/common/url_constants.h" 24 #include "chrome/common/url_constants.h"
25 #include "chrome/common/zip_reader.h"
25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/download_item.h" 27 #include "content/public/browser/download_item.h"
27 #include "content/public/browser/page_navigator.h" 28 #include "content/public/browser/page_navigator.h"
28 #include "content/public/common/url_fetcher.h" 29 #include "content/public/common/url_fetcher.h"
29 #include "content/public/common/url_fetcher_delegate.h" 30 #include "content/public/common/url_fetcher_delegate.h"
30 #include "net/base/load_flags.h" 31 #include "net/base/load_flags.h"
31 #include "net/base/x509_cert_types.h" 32 #include "net/base/x509_cert_types.h"
32 #include "net/base/x509_certificate.h" 33 #include "net/base/x509_certificate.h"
33 #include "net/http/http_status_code.h" 34 #include "net/http/http_status_code.h"
34 #include "net/url_request/url_request_context_getter.h" 35 #include "net/url_request/url_request_context_getter.h"
35 #include "net/url_request/url_request_status.h" 36 #include "net/url_request/url_request_status.h"
36 37
37 using content::BrowserThread; 38 using content::BrowserThread;
38 39
39 namespace { 40 namespace {
40 static const int64 kDownloadRequestTimeoutMs = 3000; 41 static const int64 kDownloadRequestTimeoutMs = 3000;
41 } // namespace 42 } // namespace
42 43
43 namespace safe_browsing { 44 namespace safe_browsing {
44 45
45 const char DownloadProtectionService::kDownloadRequestUrl[] = 46 const char DownloadProtectionService::kDownloadRequestUrl[] =
46 "https://sb-ssl.google.com/safebrowsing/clientreport/download"; 47 "https://sb-ssl.google.com/safebrowsing/clientreport/download";
47 48
48 namespace { 49 namespace {
50 bool IsArchiveFile(const FilePath& file) {
51 return file.MatchesExtension(FILE_PATH_LITERAL(".zip"));
52 }
53
49 bool IsBinaryFile(const FilePath& file) { 54 bool IsBinaryFile(const FilePath& file) {
50 return (file.MatchesExtension(FILE_PATH_LITERAL(".exe")) || 55 return (file.MatchesExtension(FILE_PATH_LITERAL(".exe")) ||
51 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) || 56 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) ||
52 file.MatchesExtension(FILE_PATH_LITERAL(".msi")) || 57 file.MatchesExtension(FILE_PATH_LITERAL(".msi")) ||
53 file.MatchesExtension(FILE_PATH_LITERAL(".crx")) || 58 file.MatchesExtension(FILE_PATH_LITERAL(".crx")) ||
54 file.MatchesExtension(FILE_PATH_LITERAL(".apk"))); 59 file.MatchesExtension(FILE_PATH_LITERAL(".apk")) ||
60 // Archives _may_ contain binaries, we'll check in
61 // ExtractFileFeatures.
62 IsArchiveFile(file));
55 } 63 }
56 64
57 ClientDownloadRequest::DownloadType GetDownloadType(const FilePath& file) { 65 ClientDownloadRequest::DownloadType GetDownloadType(const FilePath& file) {
58 DCHECK(IsBinaryFile(file)); 66 DCHECK(IsBinaryFile(file));
59 if (file.MatchesExtension(FILE_PATH_LITERAL(".apk"))) 67 if (file.MatchesExtension(FILE_PATH_LITERAL(".apk")))
60 return ClientDownloadRequest::ANDROID_APK; 68 return ClientDownloadRequest::ANDROID_APK;
61 else if (file.MatchesExtension(FILE_PATH_LITERAL(".crx"))) 69 else if (file.MatchesExtension(FILE_PATH_LITERAL(".crx")))
62 return ClientDownloadRequest::CHROME_EXTENSION; 70 return ClientDownloadRequest::CHROME_EXTENSION;
71 // For zip files, we use the ZIPPED_EXECUTABLE type since we will only send
72 // the pingback if we find an executable inside the zip archive.
73 else if (file.MatchesExtension(FILE_PATH_LITERAL(".zip")))
74 return ClientDownloadRequest::ZIPPED_EXECUTABLE;
63 return ClientDownloadRequest::WIN_EXECUTABLE; 75 return ClientDownloadRequest::WIN_EXECUTABLE;
64 } 76 }
65 77
66 // List of extensions for which we track some UMA stats. 78 // List of extensions for which we track some UMA stats.
67 enum MaliciousExtensionType { 79 enum MaliciousExtensionType {
68 EXTENSION_EXE, 80 EXTENSION_EXE,
69 EXTENSION_MSI, 81 EXTENSION_MSI,
70 EXTENSION_CAB, 82 EXTENSION_CAB,
71 EXTENSION_SYS, 83 EXTENSION_SYS,
72 EXTENSION_SCR, 84 EXTENSION_SCR,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 DOWNLOAD_HASH_CHECKS_TOTAL, 142 DOWNLOAD_HASH_CHECKS_TOTAL,
131 DOWNLOAD_HASH_CHECKS_MALWARE, 143 DOWNLOAD_HASH_CHECKS_MALWARE,
132 144
133 // Memory space for histograms is determined by the max. 145 // Memory space for histograms is determined by the max.
134 // ALWAYS ADD NEW VALUES BEFORE THIS ONE. 146 // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
135 DOWNLOAD_CHECKS_MAX 147 DOWNLOAD_CHECKS_MAX
136 }; 148 };
137 } // namespace 149 } // namespace
138 150
139 DownloadProtectionService::DownloadInfo::DownloadInfo() 151 DownloadProtectionService::DownloadInfo::DownloadInfo()
140 : total_bytes(0), user_initiated(false) {} 152 : total_bytes(0), user_initiated(false), zipped_executable(false) {}
141 153
142 DownloadProtectionService::DownloadInfo::~DownloadInfo() {} 154 DownloadProtectionService::DownloadInfo::~DownloadInfo() {}
143 155
144 std::string DownloadProtectionService::DownloadInfo::DebugString() const { 156 std::string DownloadProtectionService::DownloadInfo::DebugString() const {
145 std::string chain; 157 std::string chain;
146 for (size_t i = 0; i < download_url_chain.size(); ++i) { 158 for (size_t i = 0; i < download_url_chain.size(); ++i) {
147 chain += download_url_chain[i].spec(); 159 chain += download_url_chain[i].spec();
148 if (i < download_url_chain.size() - 1) { 160 if (i < download_url_chain.size() - 1) {
149 chain += " -> "; 161 chain += " -> ";
150 } 162 }
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 480
469 private: 481 private:
470 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; 482 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
471 friend class base::DeleteHelper<CheckClientDownloadRequest>; 483 friend class base::DeleteHelper<CheckClientDownloadRequest>;
472 484
473 virtual ~CheckClientDownloadRequest() { 485 virtual ~CheckClientDownloadRequest() {
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
475 } 487 }
476 488
477 void ExtractFileFeatures() { 489 void ExtractFileFeatures() {
490 // If we're checking an archive file, look to see if there are any
491 // executables inside. If not, we will skip the pingback for this
492 // download.
493 if (info_.target_file.MatchesExtension(FILE_PATH_LITERAL(".zip"))) {
494 ExtractZipFeatures();
495 if (!info_.zipped_executable) {
496 RecordImprovedProtectionStats(REASON_ARCHIVE_WITHOUT_BINARIES);
497 PostFinishTask(SAFE);
498 return;
499 }
500 } else {
501 DCHECK(!IsArchiveFile(info_.target_file));
502 ExtractSignatureFeatures();
503 }
504
505 // TODO(noelutz): DownloadInfo should also contain the IP address of
506 // every URL in the redirect chain. We also should check whether the
507 // download URL is hosted on the internal network.
508 BrowserThread::PostTask(
509 BrowserThread::IO,
510 FROM_HERE,
511 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this));
512 }
513
514 void ExtractSignatureFeatures() {
515 base::TimeTicks start_time = base::TimeTicks::Now();
478 signature_util_->CheckSignature(info_.local_file, &signature_info_); 516 signature_util_->CheckSignature(info_.local_file, &signature_info_);
479 bool is_signed = (signature_info_.certificate_chain_size() > 0); 517 bool is_signed = (signature_info_.certificate_chain_size() > 0);
480 if (is_signed) { 518 if (is_signed) {
481 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); 519 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value();
482 } else { 520 } else {
483 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); 521 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value();
484 } 522 }
485 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); 523 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed);
524 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractSignatureFeaturesTime",
525 base::TimeTicks::Now() - start_time);
526 }
486 527
487 // TODO(noelutz): DownloadInfo should also contain the IP address of every 528 void ExtractZipFeatures() {
488 // URL in the redirect chain. We also should check whether the download 529 base::TimeTicks start_time = base::TimeTicks::Now();
489 // URL is hosted on the internal network. 530 zip::ZipReader reader;
490 BrowserThread::PostTask( 531 if (reader.Open(info_.local_file)) {
491 BrowserThread::IO, 532 for (; reader.HasMore(); reader.AdvanceToNextEntry()) {
492 FROM_HERE, 533 if (!reader.OpenCurrentEntryInZip()) {
493 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); 534 VLOG(1) << "Failed to open current entry in zip file: "
535 << info_.local_file.value();
536 continue;
537 }
538 const FilePath& file = reader.current_entry_info()->file_path();
539 // Don't consider an archived archive to be executable.
mattm 2012/05/12 00:47:06 maybe add a histogram for archived archives too?
Brian Ryner 2012/05/15 00:58:34 Done.
540 if (IsBinaryFile(file) && !IsArchiveFile(file)) {
541 VLOG(2) << "Downloaded a zipped executable: "
542 << info_.local_file.value();
543 info_.zipped_executable = true;
544 break;
545 } else {
546 VLOG(3) << "Ignoring non-binary file: " << file.value();
547 }
548 }
549 } else {
550 VLOG(1) << "Failed to open zip file: " << info_.local_file.value();
551 }
552 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable",
553 info_.zipped_executable);
554 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime",
555 base::TimeTicks::Now() - start_time);
494 } 556 }
495 557
496 void CheckWhitelists() { 558 void CheckWhitelists() {
497 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
498 DownloadCheckResultReason reason = REASON_MAX; 560 DownloadCheckResultReason reason = REASON_MAX;
499 if (!sb_service_.get()) { 561 if (!sb_service_.get()) {
500 reason = REASON_SB_DISABLED; 562 reason = REASON_SB_DISABLED;
501 } else { 563 } else {
502 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { 564 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) {
503 const GURL& url = info_.download_url_chain[i]; 565 const GURL& url = info_.download_url_chain[i];
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 // Currently, the UI only works on Windows. On Linux and Mac we still 805 // Currently, the UI only works on Windows. On Linux and Mac we still
744 // want to show the dangerous file type warning if the file is possibly 806 // want to show the dangerous file type warning if the file is possibly
745 // dangerous which means we have to always return false here. 807 // dangerous which means we have to always return false here.
746 #if defined(OS_WIN) 808 #if defined(OS_WIN)
747 DownloadCheckResultReason reason = REASON_MAX; 809 DownloadCheckResultReason reason = REASON_MAX;
748 ClientDownloadRequest::DownloadType type = 810 ClientDownloadRequest::DownloadType type =
749 ClientDownloadRequest::WIN_EXECUTABLE; 811 ClientDownloadRequest::WIN_EXECUTABLE;
750 return (CheckClientDownloadRequest::IsSupportedDownload(info, 812 return (CheckClientDownloadRequest::IsSupportedDownload(info,
751 &reason, 813 &reason,
752 &type) && 814 &type) &&
753 ClientDownloadRequest::WIN_EXECUTABLE == type); 815 ClientDownloadRequest::WIN_EXECUTABLE == type ||
816 ClientDownloadRequest::ZIPPED_EXECUTABLE == type);
754 #else 817 #else
755 return false; 818 return false;
756 #endif 819 #endif
757 } 820 }
758 821
759 void DownloadProtectionService::CancelPendingRequests() { 822 void DownloadProtectionService::CancelPendingRequests() {
760 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
761 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = 824 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it =
762 download_requests_.begin(); 825 download_requests_.begin();
763 it != download_requests_.end();) { 826 it != download_requests_.end();) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 920
858 std::string issuer_fp = base::HexEncode(issuer.fingerprint().data, 921 std::string issuer_fp = base::HexEncode(issuer.fingerprint().data,
859 sizeof(issuer.fingerprint().data)); 922 sizeof(issuer.fingerprint().data));
860 for (std::set<std::string>::iterator it = paths_to_check.begin(); 923 for (std::set<std::string>::iterator it = paths_to_check.begin();
861 it != paths_to_check.end(); ++it) { 924 it != paths_to_check.end(); ++it) {
862 whitelist_strings->push_back("cert/" + issuer_fp + *it); 925 whitelist_strings->push_back("cert/" + issuer_fp + *it);
863 } 926 }
864 } 927 }
865 928
866 } // namespace safe_browsing 929 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698