| 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/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/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 public content::URLFetcherDelegate { | 60 public content::URLFetcherDelegate { |
| 61 public: | 61 public: |
| 62 CheckClientDownloadRequest(const DownloadInfo& info, | 62 CheckClientDownloadRequest(const DownloadInfo& info, |
| 63 const CheckDownloadCallback& callback, | 63 const CheckDownloadCallback& callback, |
| 64 DownloadProtectionService* service, | 64 DownloadProtectionService* service, |
| 65 SafeBrowsingService* sb_service) | 65 SafeBrowsingService* sb_service) |
| 66 : info_(info), | 66 : info_(info), |
| 67 callback_(callback), | 67 callback_(callback), |
| 68 service_(service), | 68 service_(service), |
| 69 sb_service_(sb_service), | 69 sb_service_(sb_service), |
| 70 pingback_enabled_(service_->enabled()) { | 70 pingback_enabled_(service_->enabled()), |
| 71 is_signed_(false) { |
| 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 72 } | 73 } |
| 73 | 74 |
| 74 void Start() { | 75 void Start() { |
| 75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 76 // TODO(noelutz): implement some cache to make sure we don't issue the same | 77 // TODO(noelutz): implement some cache to make sure we don't issue the same |
| 77 // request over and over again if a user downloads the same binary multiple | 78 // request over and over again if a user downloads the same binary multiple |
| 78 // times. | 79 // times. |
| 79 if (info_.download_url_chain.empty()) { | 80 if (info_.download_url_chain.empty()) { |
| 80 RecordStats(REASON_INVALID_URL); | 81 RecordStats(REASON_INVALID_URL); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 private: | 156 private: |
| 156 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | 157 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
| 157 friend class DeleteTask<CheckClientDownloadRequest>; | 158 friend class DeleteTask<CheckClientDownloadRequest>; |
| 158 | 159 |
| 159 virtual ~CheckClientDownloadRequest() { | 160 virtual ~CheckClientDownloadRequest() { |
| 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 161 } | 162 } |
| 162 | 163 |
| 163 void ExtractFileFeatures() { | 164 void ExtractFileFeatures() { |
| 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 165 bool is_signed; | |
| 166 if (safe_browsing::signature_util::IsSigned(info_.local_file)) { | 166 if (safe_browsing::signature_util::IsSigned(info_.local_file)) { |
| 167 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); | 167 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); |
| 168 is_signed = true; | 168 is_signed_ = true; |
| 169 } else { | 169 } else { |
| 170 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); | 170 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); |
| 171 is_signed = false; | 171 is_signed_ = false; |
| 172 } | 172 } |
| 173 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); | 173 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed_); |
| 174 | 174 |
| 175 // TODO(noelutz): DownloadInfo should also contain the IP address of every | 175 // TODO(noelutz): DownloadInfo should also contain the IP address of every |
| 176 // URL in the redirect chain. We also should check whether the download | 176 // URL in the redirect chain. We also should check whether the download |
| 177 // URL is hosted on the internal network. | 177 // URL is hosted on the internal network. |
| 178 BrowserThread::PostTask( | 178 BrowserThread::PostTask( |
| 179 BrowserThread::IO, | 179 BrowserThread::IO, |
| 180 FROM_HERE, | 180 FROM_HERE, |
| 181 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); | 181 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
| 182 } | 182 } |
| 183 | 183 |
| 184 void CheckWhitelists() { | 184 void CheckWhitelists() { |
| 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 186 DownloadCheckResultReason reason = REASON_MAX; | 186 DownloadCheckResultReason reason = REASON_MAX; |
| 187 if (!pingback_enabled_ || !sb_service_.get()) { | 187 if (!sb_service_.get()) { |
| 188 reason = REASON_SB_DISABLED; | 188 reason = REASON_SB_DISABLED; |
| 189 } else { | 189 } else { |
| 190 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 190 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { |
| 191 const GURL& url = info_.download_url_chain[i]; | 191 const GURL& url = info_.download_url_chain[i]; |
| 192 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { | 192 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { |
| 193 reason = REASON_WHITELISTED_URL; | 193 reason = REASON_WHITELISTED_URL; |
| 194 break; | 194 break; |
| 195 } | 195 } |
| 196 } | 196 } |
| 197 if (info_.referrer_url.is_valid() && | 197 if (info_.referrer_url.is_valid() && reason == REASON_MAX && |
| 198 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { | 198 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { |
| 199 reason = REASON_WHITELISTED_REFERRER; | 199 reason = REASON_WHITELISTED_REFERRER; |
| 200 } | 200 } |
| 201 if (reason != REASON_MAX || is_signed_) { |
| 202 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); |
| 203 } |
| 201 } | 204 } |
| 202 if (reason != REASON_MAX) { | 205 if (reason != REASON_MAX) { |
| 203 RecordStats(reason); | 206 RecordStats(reason); |
| 204 PostFinishTask(SAFE); | 207 PostFinishTask(SAFE); |
| 205 return; | 208 } else if (!pingback_enabled_) { |
| 209 RecordStats(REASON_SB_DISABLED); |
| 210 PostFinishTask(SAFE); |
| 211 } else { |
| 212 // TODO(noelutz): check signature and CA against whitelist. |
| 213 |
| 214 // The URLFetcher is owned by the UI thread, so post a message to |
| 215 // start the pingback. |
| 216 BrowserThread::PostTask( |
| 217 BrowserThread::UI, |
| 218 FROM_HERE, |
| 219 base::Bind(&CheckClientDownloadRequest::SendRequest, this)); |
| 206 } | 220 } |
| 207 | |
| 208 // TODO(noelutz): check signature and CA against whitelist. | |
| 209 | |
| 210 // The URLFetcher is owned by the UI thread, so post a message to | |
| 211 // start the pingback. | |
| 212 BrowserThread::PostTask( | |
| 213 BrowserThread::UI, | |
| 214 FROM_HERE, | |
| 215 base::Bind(&CheckClientDownloadRequest::SendRequest, this)); | |
| 216 } | 221 } |
| 217 | 222 |
| 218 void SendRequest() { | 223 void SendRequest() { |
| 219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 220 | 225 |
| 221 // This is our last chance to check whether the request has been canceled | 226 // This is our last chance to check whether the request has been canceled |
| 222 // before sending it. | 227 // before sending it. |
| 223 if (!service_) { | 228 if (!service_) { |
| 229 RecordStats(REASON_REQUEST_CANCELED); |
| 224 FinishRequest(SAFE); | 230 FinishRequest(SAFE); |
| 225 return; | 231 return; |
| 226 } | 232 } |
| 227 | 233 |
| 228 ClientDownloadRequest request; | 234 ClientDownloadRequest request; |
| 229 request.set_url(info_.download_url_chain.back().spec()); | 235 request.set_url(info_.download_url_chain.back().spec()); |
| 230 request.mutable_digests()->set_sha256(info_.sha256_hash); | 236 request.mutable_digests()->set_sha256(info_.sha256_hash); |
| 231 request.set_length(info_.total_bytes); | 237 request.set_length(info_.total_bytes); |
| 232 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 238 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { |
| 233 ClientDownloadRequest::Resource* resource = request.add_resources(); | 239 ClientDownloadRequest::Resource* resource = request.add_resources(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 288 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
| 283 reason, | 289 reason, |
| 284 REASON_MAX); | 290 REASON_MAX); |
| 285 } | 291 } |
| 286 | 292 |
| 287 DownloadInfo info_; | 293 DownloadInfo info_; |
| 288 CheckDownloadCallback callback_; | 294 CheckDownloadCallback callback_; |
| 289 // Will be NULL if the request has been canceled. | 295 // Will be NULL if the request has been canceled. |
| 290 DownloadProtectionService* service_; | 296 DownloadProtectionService* service_; |
| 291 scoped_refptr<SafeBrowsingService> sb_service_; | 297 scoped_refptr<SafeBrowsingService> sb_service_; |
| 292 bool pingback_enabled_; | 298 const bool pingback_enabled_; |
| 299 bool is_signed_; |
| 293 scoped_ptr<content::URLFetcher> fetcher_; | 300 scoped_ptr<content::URLFetcher> fetcher_; |
| 294 | 301 |
| 295 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); | 302 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); |
| 296 }; | 303 }; |
| 297 | 304 |
| 298 DownloadProtectionService::DownloadProtectionService( | 305 DownloadProtectionService::DownloadProtectionService( |
| 299 SafeBrowsingService* sb_service, | 306 SafeBrowsingService* sb_service, |
| 300 net::URLRequestContextGetter* request_context_getter) | 307 net::URLRequestContextGetter* request_context_getter) |
| 301 : sb_service_(sb_service), | 308 : sb_service_(sb_service), |
| 302 request_context_getter_(request_context_getter), | 309 request_context_getter_(request_context_getter), |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 void DownloadProtectionService::RequestFinished( | 347 void DownloadProtectionService::RequestFinished( |
| 341 CheckClientDownloadRequest* request) { | 348 CheckClientDownloadRequest* request) { |
| 342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 343 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 350 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
| 344 download_requests_.find(request); | 351 download_requests_.find(request); |
| 345 DCHECK(it != download_requests_.end()); | 352 DCHECK(it != download_requests_.end()); |
| 346 download_requests_.erase(*it); | 353 download_requests_.erase(*it); |
| 347 } | 354 } |
| 348 | 355 |
| 349 } // namespace safe_browsing | 356 } // namespace safe_browsing |
| OLD | NEW |