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

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: Merge, fix readonly folder bug and other issues 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 ( 55 return (
51 // Executable extensions for MS Windows. 56 // Executable extensions for MS Windows.
52 file.MatchesExtension(FILE_PATH_LITERAL(".bas")) || 57 file.MatchesExtension(FILE_PATH_LITERAL(".bas")) ||
53 file.MatchesExtension(FILE_PATH_LITERAL(".bat")) || 58 file.MatchesExtension(FILE_PATH_LITERAL(".bat")) ||
54 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) || 59 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) ||
55 file.MatchesExtension(FILE_PATH_LITERAL(".cmd")) || 60 file.MatchesExtension(FILE_PATH_LITERAL(".cmd")) ||
56 file.MatchesExtension(FILE_PATH_LITERAL(".com")) || 61 file.MatchesExtension(FILE_PATH_LITERAL(".com")) ||
57 file.MatchesExtension(FILE_PATH_LITERAL(".exe")) || 62 file.MatchesExtension(FILE_PATH_LITERAL(".exe")) ||
58 file.MatchesExtension(FILE_PATH_LITERAL(".hta")) || 63 file.MatchesExtension(FILE_PATH_LITERAL(".hta")) ||
59 file.MatchesExtension(FILE_PATH_LITERAL(".msi")) || 64 file.MatchesExtension(FILE_PATH_LITERAL(".msi")) ||
60 file.MatchesExtension(FILE_PATH_LITERAL(".pif")) || 65 file.MatchesExtension(FILE_PATH_LITERAL(".pif")) ||
61 file.MatchesExtension(FILE_PATH_LITERAL(".reg")) || 66 file.MatchesExtension(FILE_PATH_LITERAL(".reg")) ||
62 file.MatchesExtension(FILE_PATH_LITERAL(".scr")) || 67 file.MatchesExtension(FILE_PATH_LITERAL(".scr")) ||
63 file.MatchesExtension(FILE_PATH_LITERAL(".vb")) || 68 file.MatchesExtension(FILE_PATH_LITERAL(".vb")) ||
64 file.MatchesExtension(FILE_PATH_LITERAL(".vbs")) || 69 file.MatchesExtension(FILE_PATH_LITERAL(".vbs")) ||
65 // Chrome extensions and android APKs are also reported. 70 // Chrome extensions and android APKs are also reported.
66 file.MatchesExtension(FILE_PATH_LITERAL(".crx")) || 71 file.MatchesExtension(FILE_PATH_LITERAL(".crx")) ||
67 file.MatchesExtension(FILE_PATH_LITERAL(".apk"))); 72 file.MatchesExtension(FILE_PATH_LITERAL(".apk")) ||
73 // Archives _may_ contain binaries, we'll check in ExtractFileFeatures.
74 IsArchiveFile(file));
68 } 75 }
69 76
70 ClientDownloadRequest::DownloadType GetDownloadType(const FilePath& file) { 77 ClientDownloadRequest::DownloadType GetDownloadType(const FilePath& file) {
71 DCHECK(IsBinaryFile(file)); 78 DCHECK(IsBinaryFile(file));
72 if (file.MatchesExtension(FILE_PATH_LITERAL(".apk"))) 79 if (file.MatchesExtension(FILE_PATH_LITERAL(".apk")))
73 return ClientDownloadRequest::ANDROID_APK; 80 return ClientDownloadRequest::ANDROID_APK;
74 else if (file.MatchesExtension(FILE_PATH_LITERAL(".crx"))) 81 else if (file.MatchesExtension(FILE_PATH_LITERAL(".crx")))
75 return ClientDownloadRequest::CHROME_EXTENSION; 82 return ClientDownloadRequest::CHROME_EXTENSION;
83 // For zip files, we use the ZIPPED_EXECUTABLE type since we will only send
84 // the pingback if we find an executable inside the zip archive.
85 else if (file.MatchesExtension(FILE_PATH_LITERAL(".zip")))
86 return ClientDownloadRequest::ZIPPED_EXECUTABLE;
76 return ClientDownloadRequest::WIN_EXECUTABLE; 87 return ClientDownloadRequest::WIN_EXECUTABLE;
77 } 88 }
78 89
79 // List of extensions for which we track some UMA stats. 90 // List of extensions for which we track some UMA stats.
80 enum MaliciousExtensionType { 91 enum MaliciousExtensionType {
81 EXTENSION_EXE, 92 EXTENSION_EXE,
82 EXTENSION_MSI, 93 EXTENSION_MSI,
83 EXTENSION_CAB, 94 EXTENSION_CAB,
84 EXTENSION_SYS, 95 EXTENSION_SYS,
85 EXTENSION_SCR, 96 EXTENSION_SCR,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 DOWNLOAD_HASH_CHECKS_TOTAL, 154 DOWNLOAD_HASH_CHECKS_TOTAL,
144 DOWNLOAD_HASH_CHECKS_MALWARE, 155 DOWNLOAD_HASH_CHECKS_MALWARE,
145 156
146 // Memory space for histograms is determined by the max. 157 // Memory space for histograms is determined by the max.
147 // ALWAYS ADD NEW VALUES BEFORE THIS ONE. 158 // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
148 DOWNLOAD_CHECKS_MAX 159 DOWNLOAD_CHECKS_MAX
149 }; 160 };
150 } // namespace 161 } // namespace
151 162
152 DownloadProtectionService::DownloadInfo::DownloadInfo() 163 DownloadProtectionService::DownloadInfo::DownloadInfo()
153 : total_bytes(0), user_initiated(false) {} 164 : total_bytes(0), user_initiated(false), zipped_executable(false) {}
154 165
155 DownloadProtectionService::DownloadInfo::~DownloadInfo() {} 166 DownloadProtectionService::DownloadInfo::~DownloadInfo() {}
156 167
157 std::string DownloadProtectionService::DownloadInfo::DebugString() const { 168 std::string DownloadProtectionService::DownloadInfo::DebugString() const {
158 std::string chain; 169 std::string chain;
159 for (size_t i = 0; i < download_url_chain.size(); ++i) { 170 for (size_t i = 0; i < download_url_chain.size(); ++i) {
160 chain += download_url_chain[i].spec(); 171 chain += download_url_chain[i].spec();
161 if (i < download_url_chain.size() - 1) { 172 if (i < download_url_chain.size() - 1) {
162 chain += " -> "; 173 chain += " -> ";
163 } 174 }
164 } 175 }
165 return base::StringPrintf( 176 return base::StringPrintf(
166 "DownloadInfo {addr:0x%p, download_url_chain:[%s], local_file:%s, " 177 "DownloadInfo {addr:0x%p, download_url_chain:[%s], local_file:%s, "
167 "target_file:%s, referrer_url:%s, sha256_hash:%s, total_bytes:%" PRId64 178 "target_file:%s, referrer_url:%s, sha256_hash:%s, total_bytes:%" PRId64
asanka 2012/05/16 20:28:18 Drive by nit: "%s" doesn't work with FilePath::Cha
Brian Ryner 2012/05/16 20:39:02 Fixed by switching to PRFilePath. Thanks for catc
168 ", user_initiated: %s}", 179 ", user_initiated: %s, zipped_executable: %s}",
169 reinterpret_cast<const void*>(this), 180 reinterpret_cast<const void*>(this),
170 chain.c_str(), 181 chain.c_str(),
171 local_file.value().c_str(), 182 local_file.value().c_str(),
172 target_file.value().c_str(), 183 target_file.value().c_str(),
173 referrer_url.spec().c_str(), 184 referrer_url.spec().c_str(),
174 base::HexEncode(sha256_hash.data(), sha256_hash.size()).c_str(), 185 base::HexEncode(sha256_hash.data(), sha256_hash.size()).c_str(),
175 total_bytes, 186 total_bytes,
176 user_initiated ? "true" : "false"); 187 user_initiated ? "true" : "false",
188 zipped_executable ? "true" : "false");
177 } 189 }
178 190
179 // static 191 // static
180 DownloadProtectionService::DownloadInfo 192 DownloadProtectionService::DownloadInfo
181 DownloadProtectionService::DownloadInfo::FromDownloadItem( 193 DownloadProtectionService::DownloadInfo::FromDownloadItem(
182 const content::DownloadItem& item) { 194 const content::DownloadItem& item) {
183 DownloadInfo download_info; 195 DownloadInfo download_info;
184 download_info.target_file = item.GetTargetFilePath(); 196 download_info.target_file = item.GetTargetFilePath();
185 download_info.sha256_hash = item.GetHash(); 197 download_info.sha256_hash = item.GetHash();
186 download_info.local_file = item.GetFullPath(); 198 download_info.local_file = item.GetFullPath();
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 493
482 private: 494 private:
483 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; 495 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
484 friend class base::DeleteHelper<CheckClientDownloadRequest>; 496 friend class base::DeleteHelper<CheckClientDownloadRequest>;
485 497
486 virtual ~CheckClientDownloadRequest() { 498 virtual ~CheckClientDownloadRequest() {
487 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
488 } 500 }
489 501
490 void ExtractFileFeatures() { 502 void ExtractFileFeatures() {
503 // If we're checking an archive file, look to see if there are any
504 // executables inside. If not, we will skip the pingback for this
505 // download.
506 if (info_.target_file.MatchesExtension(FILE_PATH_LITERAL(".zip"))) {
507 ExtractZipFeatures();
508 if (!info_.zipped_executable) {
509 RecordImprovedProtectionStats(REASON_ARCHIVE_WITHOUT_BINARIES);
510 PostFinishTask(SAFE);
511 return;
512 }
513 } else {
514 DCHECK(!IsArchiveFile(info_.target_file));
515 ExtractSignatureFeatures();
516 }
517
518 // TODO(noelutz): DownloadInfo should also contain the IP address of
519 // every URL in the redirect chain. We also should check whether the
520 // download URL is hosted on the internal network.
521 BrowserThread::PostTask(
522 BrowserThread::IO,
523 FROM_HERE,
524 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this));
525 }
526
527 void ExtractSignatureFeatures() {
528 base::TimeTicks start_time = base::TimeTicks::Now();
491 signature_util_->CheckSignature(info_.local_file, &signature_info_); 529 signature_util_->CheckSignature(info_.local_file, &signature_info_);
492 bool is_signed = (signature_info_.certificate_chain_size() > 0); 530 bool is_signed = (signature_info_.certificate_chain_size() > 0);
493 if (is_signed) { 531 if (is_signed) {
494 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); 532 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value();
495 } else { 533 } else {
496 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); 534 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value();
497 } 535 }
498 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); 536 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed);
537 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractSignatureFeaturesTime",
538 base::TimeTicks::Now() - start_time);
539 }
499 540
500 // TODO(noelutz): DownloadInfo should also contain the IP address of every 541 void ExtractZipFeatures() {
501 // URL in the redirect chain. We also should check whether the download 542 base::TimeTicks start_time = base::TimeTicks::Now();
502 // URL is hosted on the internal network. 543 zip::ZipReader reader;
503 BrowserThread::PostTask( 544 bool zip_file_has_archive = false;
504 BrowserThread::IO, 545 if (reader.Open(info_.local_file)) {
505 FROM_HERE, 546 for (; reader.HasMore(); reader.AdvanceToNextEntry()) {
506 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); 547 if (!reader.OpenCurrentEntryInZip()) {
548 VLOG(1) << "Failed to open current entry in zip file: "
549 << info_.local_file.value();
550 continue;
551 }
552 const FilePath& file = reader.current_entry_info()->file_path();
553 if (IsBinaryFile(file)) {
554 // Don't consider an archived archive to be executable, but record
555 // a histogram.
556 if (IsArchiveFile(file)) {
557 zip_file_has_archive = true;
558 } else {
559 VLOG(2) << "Downloaded a zipped executable: "
560 << info_.local_file.value();
561 info_.zipped_executable = true;
562 break;
563 }
564 } else {
565 VLOG(3) << "Ignoring non-binary file: " << file.value();
566 }
567 }
568 } else {
569 VLOG(1) << "Failed to open zip file: " << info_.local_file.value();
570 }
571 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable",
572 info_.zipped_executable);
573 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable",
574 zip_file_has_archive && !info_.zipped_executable);
575 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime",
576 base::TimeTicks::Now() - start_time);
507 } 577 }
508 578
509 void CheckWhitelists() { 579 void CheckWhitelists() {
510 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
511 DownloadCheckResultReason reason = REASON_MAX; 581 DownloadCheckResultReason reason = REASON_MAX;
512 if (!sb_service_.get()) { 582 if (!sb_service_.get()) {
513 reason = REASON_SB_DISABLED; 583 reason = REASON_SB_DISABLED;
514 } else { 584 } else {
515 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { 585 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) {
516 const GURL& url = info_.download_url_chain[i]; 586 const GURL& url = info_.download_url_chain[i];
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 // Currently, the UI only works on Windows. On Linux and Mac we still 826 // Currently, the UI only works on Windows. On Linux and Mac we still
757 // want to show the dangerous file type warning if the file is possibly 827 // want to show the dangerous file type warning if the file is possibly
758 // dangerous which means we have to always return false here. 828 // dangerous which means we have to always return false here.
759 #if defined(OS_WIN) 829 #if defined(OS_WIN)
760 DownloadCheckResultReason reason = REASON_MAX; 830 DownloadCheckResultReason reason = REASON_MAX;
761 ClientDownloadRequest::DownloadType type = 831 ClientDownloadRequest::DownloadType type =
762 ClientDownloadRequest::WIN_EXECUTABLE; 832 ClientDownloadRequest::WIN_EXECUTABLE;
763 return (CheckClientDownloadRequest::IsSupportedDownload(info, 833 return (CheckClientDownloadRequest::IsSupportedDownload(info,
764 &reason, 834 &reason,
765 &type) && 835 &type) &&
766 ClientDownloadRequest::WIN_EXECUTABLE == type); 836 (ClientDownloadRequest::WIN_EXECUTABLE == type ||
837 ClientDownloadRequest::ZIPPED_EXECUTABLE == type));
767 #else 838 #else
768 return false; 839 return false;
769 #endif 840 #endif
770 } 841 }
771 842
772 void DownloadProtectionService::CancelPendingRequests() { 843 void DownloadProtectionService::CancelPendingRequests() {
773 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
774 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = 845 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it =
775 download_requests_.begin(); 846 download_requests_.begin();
776 it != download_requests_.end();) { 847 it != download_requests_.end();) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
870 941
871 std::string issuer_fp = base::HexEncode(issuer.fingerprint().data, 942 std::string issuer_fp = base::HexEncode(issuer.fingerprint().data,
872 sizeof(issuer.fingerprint().data)); 943 sizeof(issuer.fingerprint().data));
873 for (std::set<std::string>::iterator it = paths_to_check.begin(); 944 for (std::set<std::string>::iterator it = paths_to_check.begin();
874 it != paths_to_check.end(); ++it) { 945 it != paths_to_check.end(); ++it) {
875 whitelist_strings->push_back("cert/" + issuer_fp + *it); 946 whitelist_strings->push_back("cert/" + issuer_fp + *it);
876 } 947 }
877 } 948 }
878 949
879 } // namespace safe_browsing 950 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698