Chromium Code Reviews| 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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 | 109 |
| 110 class DownloadProtectionService::CheckClientDownloadRequest | 110 class DownloadProtectionService::CheckClientDownloadRequest |
| 111 : public base::RefCountedThreadSafe< | 111 : public base::RefCountedThreadSafe< |
| 112 DownloadProtectionService::CheckClientDownloadRequest, | 112 DownloadProtectionService::CheckClientDownloadRequest, |
| 113 BrowserThread::DeleteOnUIThread>, | 113 BrowserThread::DeleteOnUIThread>, |
| 114 public content::URLFetcherDelegate { | 114 public content::URLFetcherDelegate { |
| 115 public: | 115 public: |
| 116 CheckClientDownloadRequest(const DownloadInfo& info, | 116 CheckClientDownloadRequest(const DownloadInfo& info, |
| 117 const CheckDownloadCallback& callback, | 117 const CheckDownloadCallback& callback, |
| 118 DownloadProtectionService* service, | 118 DownloadProtectionService* service, |
| 119 SafeBrowsingService* sb_service) | 119 SafeBrowsingService* sb_service, |
| 120 SignatureUtil* signature_util) | |
| 120 : info_(info), | 121 : info_(info), |
| 121 callback_(callback), | 122 callback_(callback), |
| 122 service_(service), | 123 service_(service), |
| 124 signature_util_(signature_util), | |
| 123 sb_service_(sb_service), | 125 sb_service_(sb_service), |
| 124 pingback_enabled_(service_->enabled()), | 126 pingback_enabled_(service_->enabled()) { |
| 125 is_signed_(false) { | |
| 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 127 } | 128 } |
| 128 | 129 |
| 129 void Start() { | 130 void Start() { |
| 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 131 // TODO(noelutz): implement some cache to make sure we don't issue the same | 132 // TODO(noelutz): implement some cache to make sure we don't issue the same |
| 132 // request over and over again if a user downloads the same binary multiple | 133 // request over and over again if a user downloads the same binary multiple |
| 133 // times. | 134 // times. |
| 134 if (info_.download_url_chain.empty()) { | 135 if (info_.download_url_chain.empty()) { |
| 135 RecordStats(REASON_INVALID_URL); | 136 RecordStats(REASON_INVALID_URL); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 private: | 213 private: |
| 213 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | 214 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
| 214 friend class DeleteTask<CheckClientDownloadRequest>; | 215 friend class DeleteTask<CheckClientDownloadRequest>; |
| 215 | 216 |
| 216 virtual ~CheckClientDownloadRequest() { | 217 virtual ~CheckClientDownloadRequest() { |
| 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 218 } | 219 } |
| 219 | 220 |
| 220 void ExtractFileFeatures() { | 221 void ExtractFileFeatures() { |
| 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 222 if (safe_browsing::signature_util::IsSigned(info_.local_file)) { | 223 signature_util_->CheckSignature(info_.local_file, &signature_info_); |
| 224 bool is_signed; | |
| 225 if (signature_info_.has_certificate_contents()) { | |
| 223 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); | 226 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); |
| 224 is_signed_ = true; | 227 is_signed = true; |
| 225 } else { | 228 } else { |
| 226 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); | 229 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); |
| 227 is_signed_ = false; | 230 is_signed = false; |
|
noelutz
2011/11/04 04:41:11
nit: I guess you don't really need that boolean an
Brian Ryner
2011/11/04 22:20:30
I left it as a convenience, that way we only need
| |
| 228 } | 231 } |
| 229 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed_); | 232 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); |
| 230 | 233 |
| 231 // TODO(noelutz): DownloadInfo should also contain the IP address of every | 234 // TODO(noelutz): DownloadInfo should also contain the IP address of every |
| 232 // URL in the redirect chain. We also should check whether the download | 235 // URL in the redirect chain. We also should check whether the download |
| 233 // URL is hosted on the internal network. | 236 // URL is hosted on the internal network. |
| 234 BrowserThread::PostTask( | 237 BrowserThread::PostTask( |
| 235 BrowserThread::IO, | 238 BrowserThread::IO, |
| 236 FROM_HERE, | 239 FROM_HERE, |
| 237 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); | 240 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
| 238 } | 241 } |
| 239 | 242 |
| 240 void CheckWhitelists() { | 243 void CheckWhitelists() { |
| 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 242 DownloadCheckResultReason reason = REASON_MAX; | 245 DownloadCheckResultReason reason = REASON_MAX; |
| 243 if (!sb_service_.get()) { | 246 if (!sb_service_.get()) { |
| 244 reason = REASON_SB_DISABLED; | 247 reason = REASON_SB_DISABLED; |
| 245 } else { | 248 } else { |
| 246 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 249 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { |
| 247 const GURL& url = info_.download_url_chain[i]; | 250 const GURL& url = info_.download_url_chain[i]; |
| 248 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { | 251 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { |
| 249 reason = REASON_WHITELISTED_URL; | 252 reason = REASON_WHITELISTED_URL; |
| 250 break; | 253 break; |
| 251 } | 254 } |
| 252 } | 255 } |
| 253 if (info_.referrer_url.is_valid() && reason == REASON_MAX && | 256 if (info_.referrer_url.is_valid() && reason == REASON_MAX && |
| 254 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { | 257 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { |
| 255 reason = REASON_WHITELISTED_REFERRER; | 258 reason = REASON_WHITELISTED_REFERRER; |
| 256 } | 259 } |
| 257 if (reason != REASON_MAX || is_signed_) { | 260 if (reason != REASON_MAX || signature_info_.has_certificate_contents()) { |
| 258 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); | 261 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); |
| 259 } | 262 } |
| 260 } | 263 } |
| 261 if (reason != REASON_MAX) { | 264 if (reason != REASON_MAX) { |
| 262 RecordStats(reason); | 265 RecordStats(reason); |
| 263 PostFinishTask(SAFE); | 266 PostFinishTask(SAFE); |
| 264 } else if (!pingback_enabled_) { | 267 } else if (!pingback_enabled_) { |
| 265 RecordStats(REASON_SB_DISABLED); | 268 RecordStats(REASON_SB_DISABLED); |
| 266 PostFinishTask(SAFE); | 269 PostFinishTask(SAFE); |
| 267 } else { | 270 } else { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 297 if (i == info_.download_url_chain.size() - 1) { | 300 if (i == info_.download_url_chain.size() - 1) { |
| 298 // The last URL in the chain is the download URL. | 301 // The last URL in the chain is the download URL. |
| 299 resource->set_type(ClientDownloadRequest::DOWNLOAD_URL); | 302 resource->set_type(ClientDownloadRequest::DOWNLOAD_URL); |
| 300 resource->set_referrer(info_.referrer_url.spec()); | 303 resource->set_referrer(info_.referrer_url.spec()); |
| 301 } else { | 304 } else { |
| 302 resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT); | 305 resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT); |
| 303 } | 306 } |
| 304 // TODO(noelutz): fill out the remote IP addresses. | 307 // TODO(noelutz): fill out the remote IP addresses. |
| 305 } | 308 } |
| 306 request.set_user_initiated(info_.user_initiated); | 309 request.set_user_initiated(info_.user_initiated); |
| 310 request.mutable_signature()->CopyFrom(signature_info_); | |
| 307 std::string request_data; | 311 std::string request_data; |
| 308 if (!request.SerializeToString(&request_data)) { | 312 if (!request.SerializeToString(&request_data)) { |
| 309 RecordStats(REASON_INVALID_REQUEST_PROTO); | 313 RecordStats(REASON_INVALID_REQUEST_PROTO); |
| 310 FinishRequest(SAFE); | 314 FinishRequest(SAFE); |
| 311 return; | 315 return; |
| 312 } | 316 } |
| 313 | 317 |
| 314 VLOG(2) << "Sending a request for URL: " | 318 VLOG(2) << "Sending a request for URL: " |
| 315 << info_.download_url_chain.back(); | 319 << info_.download_url_chain.back(); |
| 316 fetcher_.reset(content::URLFetcher::Create(0 /* ID used for testing */, | 320 fetcher_.reset(content::URLFetcher::Create(0 /* ID used for testing */, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 340 } | 344 } |
| 341 } | 345 } |
| 342 | 346 |
| 343 void RecordStats(DownloadCheckResultReason reason) { | 347 void RecordStats(DownloadCheckResultReason reason) { |
| 344 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 348 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
| 345 reason, | 349 reason, |
| 346 REASON_MAX); | 350 REASON_MAX); |
| 347 } | 351 } |
| 348 | 352 |
| 349 DownloadInfo info_; | 353 DownloadInfo info_; |
| 354 ClientDownloadRequest_SignatureInfo signature_info_; | |
| 350 CheckDownloadCallback callback_; | 355 CheckDownloadCallback callback_; |
| 351 // Will be NULL if the request has been canceled. | 356 // Will be NULL if the request has been canceled. |
| 352 DownloadProtectionService* service_; | 357 DownloadProtectionService* service_; |
| 358 scoped_refptr<SignatureUtil> signature_util_; | |
| 353 scoped_refptr<SafeBrowsingService> sb_service_; | 359 scoped_refptr<SafeBrowsingService> sb_service_; |
| 354 const bool pingback_enabled_; | 360 const bool pingback_enabled_; |
| 355 bool is_signed_; | |
| 356 scoped_ptr<content::URLFetcher> fetcher_; | 361 scoped_ptr<content::URLFetcher> fetcher_; |
| 357 | 362 |
| 358 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); | 363 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); |
| 359 }; | 364 }; |
| 360 | 365 |
| 361 DownloadProtectionService::DownloadProtectionService( | 366 DownloadProtectionService::DownloadProtectionService( |
| 362 SafeBrowsingService* sb_service, | 367 SafeBrowsingService* sb_service, |
| 363 net::URLRequestContextGetter* request_context_getter) | 368 net::URLRequestContextGetter* request_context_getter) |
| 364 : sb_service_(sb_service), | 369 : sb_service_(sb_service), |
| 365 request_context_getter_(request_context_getter), | 370 request_context_getter_(request_context_getter), |
| 366 enabled_(false) {} | 371 enabled_(false), |
| 372 signature_util_(new SignatureUtil()) {} | |
| 367 | 373 |
| 368 DownloadProtectionService::~DownloadProtectionService() { | 374 DownloadProtectionService::~DownloadProtectionService() { |
| 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 370 CancelPendingRequests(); | 376 CancelPendingRequests(); |
| 371 } | 377 } |
| 372 | 378 |
| 373 void DownloadProtectionService::SetEnabled(bool enabled) { | 379 void DownloadProtectionService::SetEnabled(bool enabled) { |
| 374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 375 if (enabled == enabled_) { | 381 if (enabled == enabled_) { |
| 376 return; | 382 return; |
| 377 } | 383 } |
| 378 enabled_ = enabled; | 384 enabled_ = enabled; |
| 379 if (!enabled_) { | 385 if (!enabled_) { |
| 380 CancelPendingRequests(); | 386 CancelPendingRequests(); |
| 381 } | 387 } |
| 382 } | 388 } |
| 383 | 389 |
| 384 void DownloadProtectionService::CheckClientDownload( | 390 void DownloadProtectionService::CheckClientDownload( |
| 385 const DownloadProtectionService::DownloadInfo& info, | 391 const DownloadProtectionService::DownloadInfo& info, |
| 386 const CheckDownloadCallback& callback) { | 392 const CheckDownloadCallback& callback) { |
| 387 scoped_refptr<CheckClientDownloadRequest> request( | 393 scoped_refptr<CheckClientDownloadRequest> request( |
| 388 new CheckClientDownloadRequest(info, callback, this, sb_service_)); | 394 new CheckClientDownloadRequest(info, callback, this, |
| 395 sb_service_, signature_util_.get())); | |
| 389 download_requests_.insert(request); | 396 download_requests_.insert(request); |
| 390 request->Start(); | 397 request->Start(); |
| 391 } | 398 } |
| 392 | 399 |
| 393 void DownloadProtectionService::CancelPendingRequests() { | 400 void DownloadProtectionService::CancelPendingRequests() { |
| 394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 395 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 402 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
| 396 download_requests_.begin(); | 403 download_requests_.begin(); |
| 397 it != download_requests_.end(); ++it) { | 404 it != download_requests_.end(); ++it) { |
| 398 (*it)->Cancel(); | 405 (*it)->Cancel(); |
| 399 } | 406 } |
| 400 download_requests_.clear(); | 407 download_requests_.clear(); |
| 401 } | 408 } |
| 402 | 409 |
| 403 void DownloadProtectionService::RequestFinished( | 410 void DownloadProtectionService::RequestFinished( |
| 404 CheckClientDownloadRequest* request) { | 411 CheckClientDownloadRequest* request) { |
| 405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 406 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 413 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
| 407 download_requests_.find(request); | 414 download_requests_.find(request); |
| 408 DCHECK(it != download_requests_.end()); | 415 DCHECK(it != download_requests_.end()); |
| 409 download_requests_.erase(*it); | 416 download_requests_.erase(*it); |
| 410 } | 417 } |
| 411 | 418 |
| 412 } // namespace safe_browsing | 419 } // namespace safe_browsing |
| OLD | NEW |