Commit c034c303 authored by Daniel Rubery's avatar Daniel Rubery Committed by Chromium LUCI CQ

Create DownloadRequestMaker to populate download pings

This CL refactors the CheckClientDownloadRequestBase into two separate
classes. The CheckClientDownloadRequestBase is responsible for request
logic, such as checking the allowlist and networking operations, while
the DownloadRequestMaker is responsible for assembling the actual
request proto.

Bug: 1165815

Change-Id: Iaaa43ddf65a9c808f2d50bb86800c9667f5e5d7f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2623708Reviewed-by: default avatarXinghui Lu <xinghuilu@chromium.org>
Commit-Queue: Daniel Rubery <drubery@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843085}
parent 9000e7fa
...@@ -184,6 +184,8 @@ static_library("safe_browsing") { ...@@ -184,6 +184,8 @@ static_library("safe_browsing") {
"download_protection/download_protection_util.h", "download_protection/download_protection_util.h",
"download_protection/download_reporter.cc", "download_protection/download_reporter.cc",
"download_protection/download_reporter.h", "download_protection/download_reporter.h",
"download_protection/download_request_maker.cc",
"download_protection/download_request_maker.h",
"download_protection/download_url_sb_client.cc", "download_protection/download_url_sb_client.cc",
"download_protection/download_url_sb_client.h", "download_protection/download_url_sb_client.h",
"download_protection/file_analyzer.cc", "download_protection/file_analyzer.cc",
......
...@@ -111,15 +111,12 @@ CheckClientDownloadRequest::CheckClientDownloadRequest( ...@@ -111,15 +111,12 @@ CheckClientDownloadRequest::CheckClientDownloadRequest(
: CheckClientDownloadRequestBase( : CheckClientDownloadRequestBase(
item->GetURL(), item->GetURL(),
item->GetTargetFilePath(), item->GetTargetFilePath(),
item->GetFullPath(),
{item->GetTabUrl(), item->GetTabReferrerUrl()},
item->GetMimeType(),
item->GetHash(),
content::DownloadItemUtils::GetBrowserContext(item), content::DownloadItemUtils::GetBrowserContext(item),
callback, callback,
service, service,
std::move(database_manager), std::move(database_manager),
std::move(binary_feature_extractor)), std::make_unique<DownloadRequestMaker>(binary_feature_extractor,
item)),
item_(item), item_(item),
callback_(callback) { callback_(callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -154,8 +151,7 @@ void CheckClientDownloadRequest::OnDownloadUpdated( ...@@ -154,8 +151,7 @@ void CheckClientDownloadRequest::OnDownloadUpdated(
bool CheckClientDownloadRequest::IsSupportedDownload( bool CheckClientDownloadRequest::IsSupportedDownload(
const download::DownloadItem& item, const download::DownloadItem& item,
const base::FilePath& target_path, const base::FilePath& target_path,
DownloadCheckResultReason* reason, DownloadCheckResultReason* reason) {
ClientDownloadRequest::DownloadType* type) {
if (item.GetUrlChain().empty()) { if (item.GetUrlChain().empty()) {
*reason = REASON_EMPTY_URL_CHAIN; *reason = REASON_EMPTY_URL_CHAIN;
return false; return false;
...@@ -181,7 +177,6 @@ bool CheckClientDownloadRequest::IsSupportedDownload( ...@@ -181,7 +177,6 @@ bool CheckClientDownloadRequest::IsSupportedDownload(
*reason = REASON_NOT_BINARY_FILE; *reason = REASON_NOT_BINARY_FILE;
return false; return false;
} }
*type = download_type_util::GetDownloadType(target_path);
return true; return true;
} }
...@@ -191,9 +186,8 @@ CheckClientDownloadRequest::~CheckClientDownloadRequest() { ...@@ -191,9 +186,8 @@ CheckClientDownloadRequest::~CheckClientDownloadRequest() {
} }
bool CheckClientDownloadRequest::IsSupportedDownload( bool CheckClientDownloadRequest::IsSupportedDownload(
DownloadCheckResultReason* reason, DownloadCheckResultReason* reason) {
ClientDownloadRequest::DownloadType* type) { return IsSupportedDownload(*item_, item_->GetTargetFilePath(), reason);
return IsSupportedDownload(*item_, item_->GetTargetFilePath(), reason, type);
} }
content::BrowserContext* CheckClientDownloadRequest::GetBrowserContext() const { content::BrowserContext* CheckClientDownloadRequest::GetBrowserContext() const {
...@@ -204,46 +198,6 @@ bool CheckClientDownloadRequest::IsCancelled() { ...@@ -204,46 +198,6 @@ bool CheckClientDownloadRequest::IsCancelled() {
return item_->GetState() == download::DownloadItem::CANCELLED; return item_->GetState() == download::DownloadItem::CANCELLED;
} }
void CheckClientDownloadRequest::PopulateRequest(
ClientDownloadRequest* request) {
request->mutable_digests()->set_sha256(item_->GetHash());
request->set_length(item_->GetReceivedBytes());
for (size_t i = 0; i < item_->GetUrlChain().size(); ++i) {
ClientDownloadRequest::Resource* resource = request->add_resources();
resource->set_url(SanitizeUrl(item_->GetUrlChain()[i]));
if (i == item_->GetUrlChain().size() - 1) {
// The last URL in the chain is the download URL.
resource->set_type(ClientDownloadRequest::DOWNLOAD_URL);
resource->set_referrer(SanitizeUrl(item_->GetReferrerUrl()));
DVLOG(2) << "dl url " << resource->url();
if (!item_->GetRemoteAddress().empty()) {
resource->set_remote_ip(item_->GetRemoteAddress());
DVLOG(2) << " dl url remote addr: " << resource->remote_ip();
}
DVLOG(2) << "dl referrer " << resource->referrer();
} else {
DVLOG(2) << "dl redirect " << i << " " << resource->url();
resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT);
}
}
request->set_user_initiated(item_->HasUserGesture());
auto* referrer_chain_data = static_cast<ReferrerChainData*>(
item_->GetUserData(ReferrerChainData::kDownloadReferrerChainDataKey));
if (referrer_chain_data &&
!referrer_chain_data->GetReferrerChain()->empty()) {
request->mutable_referrer_chain()->Swap(
referrer_chain_data->GetReferrerChain());
request->mutable_referrer_chain_options()
->set_recent_navigations_to_collect(
referrer_chain_data->recent_navigations_to_collect());
UMA_HISTOGRAM_COUNTS_100(
"SafeBrowsing.ReferrerURLChainSize.DownloadAttribution",
referrer_chain_data->referrer_chain_length());
}
}
base::WeakPtr<CheckClientDownloadRequestBase> base::WeakPtr<CheckClientDownloadRequestBase>
CheckClientDownloadRequest::GetWeakPtr() { CheckClientDownloadRequest::GetWeakPtr() {
return weakptr_factory_.GetWeakPtr(); return weakptr_factory_.GetWeakPtr();
...@@ -253,6 +207,9 @@ void CheckClientDownloadRequest::NotifySendRequest( ...@@ -253,6 +207,9 @@ void CheckClientDownloadRequest::NotifySendRequest(
const ClientDownloadRequest* request) { const ClientDownloadRequest* request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
service()->client_download_request_callbacks_.Notify(item_, request); service()->client_download_request_callbacks_.Notify(item_, request);
UMA_HISTOGRAM_COUNTS_100(
"SafeBrowsing.ReferrerURLChainSize.DownloadAttribution",
request->referrer_chain().size());
} }
void CheckClientDownloadRequest::SetDownloadPingToken( void CheckClientDownloadRequest::SetDownloadPingToken(
......
...@@ -43,16 +43,13 @@ class CheckClientDownloadRequest : public CheckClientDownloadRequestBase, ...@@ -43,16 +43,13 @@ class CheckClientDownloadRequest : public CheckClientDownloadRequestBase,
static bool IsSupportedDownload(const download::DownloadItem& item, static bool IsSupportedDownload(const download::DownloadItem& item,
const base::FilePath& target_path, const base::FilePath& target_path,
DownloadCheckResultReason* reason, DownloadCheckResultReason* reason);
ClientDownloadRequest::DownloadType* type);
private: private:
// CheckClientDownloadRequestBase overrides: // CheckClientDownloadRequestBase overrides:
bool IsSupportedDownload(DownloadCheckResultReason* reason, bool IsSupportedDownload(DownloadCheckResultReason* reason) override;
ClientDownloadRequest::DownloadType* type) override;
content::BrowserContext* GetBrowserContext() const override; content::BrowserContext* GetBrowserContext() const override;
bool IsCancelled() override; bool IsCancelled() override;
void PopulateRequest(ClientDownloadRequest* request) override;
base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() override; base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() override;
void NotifySendRequest(const ClientDownloadRequest* request) override; void NotifySendRequest(const ClientDownloadRequest* request) override;
......
...@@ -13,11 +13,7 @@ ...@@ -13,11 +13,7 @@
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h" #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h" #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
...@@ -128,32 +124,27 @@ bool CheckCertificateChainAgainstWhitelist( ...@@ -128,32 +124,27 @@ bool CheckCertificateChainAgainstWhitelist(
return false; return false;
} }
std::string SanitizeUrl(const std::string& url) {
return GURL(url).GetOrigin().spec();
}
} // namespace } // namespace
CheckClientDownloadRequestBase::CheckClientDownloadRequestBase( CheckClientDownloadRequestBase::CheckClientDownloadRequestBase(
GURL source_url, GURL source_url,
base::FilePath target_file_path, base::FilePath target_file_path,
base::FilePath full_path,
TabUrls tab_urls,
std::string mime_type,
std::string hash,
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
CheckDownloadCallback callback, CheckDownloadCallback callback,
DownloadProtectionService* service, DownloadProtectionService* service,
scoped_refptr<SafeBrowsingDatabaseManager> database_manager, scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor) std::unique_ptr<DownloadRequestMaker> download_request_maker)
: source_url_(std::move(source_url)), : source_url_(std::move(source_url)),
target_file_path_(std::move(target_file_path)), target_file_path_(std::move(target_file_path)),
full_path_(std::move(full_path)),
tab_url_(std::move(tab_urls.url)),
tab_referrer_url_(std::move(tab_urls.referrer)),
callback_(std::move(callback)), callback_(std::move(callback)),
service_(service), service_(service),
binary_feature_extractor_(std::move(binary_feature_extractor)),
database_manager_(std::move(database_manager)), database_manager_(std::move(database_manager)),
pingback_enabled_(service_->enabled()), pingback_enabled_(service_->enabled()),
mime_type_(mime_type), download_request_maker_(std::move(download_request_maker)) {
hash_(hash) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (browser_context) { if (browser_context) {
...@@ -161,10 +152,6 @@ CheckClientDownloadRequestBase::CheckClientDownloadRequestBase( ...@@ -161,10 +152,6 @@ CheckClientDownloadRequestBase::CheckClientDownloadRequestBase(
is_extended_reporting_ = is_extended_reporting_ =
profile && IsExtendedReportingEnabled(*profile->GetPrefs()); profile && IsExtendedReportingEnabled(*profile->GetPrefs());
is_incognito_ = browser_context->IsOffTheRecord(); is_incognito_ = browser_context->IsOffTheRecord();
is_under_advanced_protection_ =
profile &&
AdvancedProtectionStatusManagerFactory::GetForProfile(profile)
->IsUnderAdvancedProtection();
is_enhanced_protection_ = is_enhanced_protection_ =
profile && IsEnhancedProtectionEnabled(*profile->GetPrefs()); profile && IsEnhancedProtectionEnabled(*profile->GetPrefs());
signin::IdentityManager* identity_manager = signin::IdentityManager* identity_manager =
...@@ -198,13 +185,6 @@ void CheckClientDownloadRequestBase::Start() { ...@@ -198,13 +185,6 @@ void CheckClientDownloadRequestBase::Start() {
GetWeakPtr())); GetWeakPtr()));
} }
std::string CheckClientDownloadRequestBase::SanitizeUrl(const GURL& url) const {
if (type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE)
return url.GetOrigin().spec();
return ShortURLForReporting(url);
}
void CheckClientDownloadRequestBase::FinishRequest( void CheckClientDownloadRequestBase::FinishRequest(
DownloadCheckResult result, DownloadCheckResult result,
DownloadCheckResultReason reason) { DownloadCheckResultReason reason) {
...@@ -291,15 +271,8 @@ void CheckClientDownloadRequestBase::OnUrlWhitelistCheckDone( ...@@ -291,15 +271,8 @@ void CheckClientDownloadRequestBase::OnUrlWhitelistCheckDone(
} }
} }
// Continue with file analysis.
AnalyzeFile();
}
void CheckClientDownloadRequestBase::AnalyzeFile() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DownloadCheckResultReason reason = REASON_MAX; DownloadCheckResultReason reason = REASON_MAX;
if (!IsSupportedDownload(&reason, &type_)) { if (!IsSupportedDownload(&reason)) {
switch (reason) { switch (reason) {
case REASON_EMPTY_URL_CHAIN: case REASON_EMPTY_URL_CHAIN:
case REASON_INVALID_URL: case REASON_INVALID_URL:
...@@ -313,7 +286,7 @@ void CheckClientDownloadRequestBase::AnalyzeFile() { ...@@ -313,7 +286,7 @@ void CheckClientDownloadRequestBase::AnalyzeFile() {
case REASON_NOT_BINARY_FILE: case REASON_NOT_BINARY_FILE:
if (ShouldSampleUnsupportedFile(target_file_path_)) { if (ShouldSampleUnsupportedFile(target_file_path_)) {
// Send a "light ping" and don't use the verdict. // Send a "light ping" and don't use the verdict.
type_ = ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE; sampled_unsupported_file_ = true;
break; break;
} }
RecordFileExtensionType(kDownloadExtensionUmaName, target_file_path_); RecordFileExtensionType(kDownloadExtensionUmaName, target_file_path_);
...@@ -327,53 +300,57 @@ void CheckClientDownloadRequestBase::AnalyzeFile() { ...@@ -327,53 +300,57 @@ void CheckClientDownloadRequestBase::AnalyzeFile() {
} }
RecordFileExtensionType(kDownloadExtensionUmaName, target_file_path_); RecordFileExtensionType(kDownloadExtensionUmaName, target_file_path_);
file_analyzer_->Start( download_request_maker_->Start(base::BindOnce(
target_file_path_, full_path_, &CheckClientDownloadRequestBase::OnRequestBuilt, GetWeakPtr()));
base::BindOnce(
&CheckClientDownloadRequestBase::OnFileFeatureExtractionDone,
GetWeakPtr()));
} }
void CheckClientDownloadRequestBase::OnFileFeatureExtractionDone( void CheckClientDownloadRequestBase::SanitizeRequest() {
FileAnalyzer::Results results) { if (!sampled_unsupported_file_)
DCHECK_CURRENTLY_ON(BrowserThread::UI); return;
client_download_request_->set_download_type(
ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE);
if (client_download_request_->referrer_chain_size() > 0) {
SafeBrowsingNavigationObserverManager::SanitizeReferrerChain(
client_download_request_->mutable_referrer_chain());
}
client_download_request_->set_url(
SanitizeUrl(client_download_request_->url()));
for (ClientDownloadRequest::Resource& resource :
*client_download_request_->mutable_resources()) {
resource.set_url(SanitizeUrl(resource.url()));
resource.set_referrer(SanitizeUrl(resource.referrer()));
}
}
void CheckClientDownloadRequestBase::OnRequestBuilt(
std::unique_ptr<ClientDownloadRequest> request) {
client_download_request_ = std::move(request);
SanitizeRequest();
// If it's an archive with no archives or executables, finish early. // If it's an archive with no archives or executables, finish early.
if ((type_ == ClientDownloadRequest::ZIPPED_EXECUTABLE || if ((client_download_request_->download_type() ==
type_ == ClientDownloadRequest::RAR_COMPRESSED_EXECUTABLE) && ClientDownloadRequest::ZIPPED_EXECUTABLE ||
!results.archived_executable && !results.archived_archive && client_download_request_->download_type() ==
results.archive_is_valid == FileAnalyzer::ArchiveValid::VALID) { ClientDownloadRequest::RAR_COMPRESSED_EXECUTABLE) &&
client_download_request_->archive_valid() &&
std::all_of(
client_download_request_->archived_binary().begin(),
client_download_request_->archived_binary().end(),
[](const ClientDownloadRequest::ArchivedBinary& archived_binary) {
return !archived_binary.is_executable() &&
!archived_binary.is_archive();
})) {
FinishRequest(DownloadCheckResult::UNKNOWN, FinishRequest(DownloadCheckResult::UNKNOWN,
REASON_ARCHIVE_WITHOUT_BINARIES); REASON_ARCHIVE_WITHOUT_BINARIES);
return; return;
} }
// The content checks cannot determine that we decided to sample this file, so
// special case that DownloadType.
if (type_ != ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE)
type_ = results.type;
archived_executable_ = results.archived_executable;
archive_is_valid_ = results.archive_is_valid;
archived_binaries_.CopyFrom(results.archived_binaries);
signature_info_ = results.signature_info;
image_headers_.reset(new ClientDownloadRequest_ImageHeaders());
*image_headers_ = results.image_headers;
file_count_ = results.file_count;
directory_count_ = results.directory_count;
#if defined(OS_MAC)
if (!results.disk_image_signature.empty())
disk_image_signature_ =
std::make_unique<std::vector<uint8_t>>(results.disk_image_signature);
else
disk_image_signature_ = nullptr;
detached_code_signatures_.CopyFrom(results.detached_code_signatures);
#endif
content::GetIOThreadTaskRunner({})->PostTaskAndReplyWithResult( content::GetIOThreadTaskRunner({})->PostTaskAndReplyWithResult(
FROM_HERE, FROM_HERE,
base::BindOnce(&CheckCertificateChainAgainstWhitelist, signature_info_, base::BindOnce(&CheckCertificateChainAgainstWhitelist,
database_manager_), client_download_request_->signature(), database_manager_),
base::BindOnce( base::BindOnce(
&CheckClientDownloadRequestBase::OnCertificateWhitelistCheckDone, &CheckClientDownloadRequestBase::OnCertificateWhitelistCheckDone,
GetWeakPtr())); GetWeakPtr()));
...@@ -424,40 +401,6 @@ void CheckClientDownloadRequestBase::OnCertificateWhitelistCheckDone( ...@@ -424,40 +401,6 @@ void CheckClientDownloadRequestBase::OnCertificateWhitelistCheckDone(
return; return;
} }
GetTabRedirects();
}
void CheckClientDownloadRequestBase::GetTabRedirects() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!tab_url_.is_valid()) {
OnGotTabRedirects({});
return;
}
Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
history::HistoryService* history = HistoryServiceFactory::GetForProfile(
profile, ServiceAccessType::EXPLICIT_ACCESS);
if (!history) {
OnGotTabRedirects({});
return;
}
history->QueryRedirectsTo(
tab_url_,
base::BindOnce(&CheckClientDownloadRequestBase::OnGotTabRedirects,
GetWeakPtr()),
&request_tracker_);
}
void CheckClientDownloadRequestBase::OnGotTabRedirects(
history::RedirectList redirect_list) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!redirect_list.empty()) {
tab_redirects_.insert(tab_redirects_.end(), redirect_list.rbegin(),
redirect_list.rend());
}
if (is_enhanced_protection_ && token_fetcher_ && if (is_enhanced_protection_ && token_fetcher_ &&
base::FeatureList::IsEnabled(kDownloadRequestWithToken)) { base::FeatureList::IsEnabled(kDownloadRequestWithToken)) {
token_fetcher_->Start( token_fetcher_->Start(
...@@ -483,78 +426,12 @@ void CheckClientDownloadRequestBase::SendRequest() { ...@@ -483,78 +426,12 @@ void CheckClientDownloadRequestBase::SendRequest() {
return; return;
} }
auto request = std::make_unique<ClientDownloadRequest>(); client_download_request_->set_skipped_url_whitelist(skipped_url_whitelist_);
auto population = is_enhanced_protection_ client_download_request_->set_skipped_certificate_whitelist(
? ChromeUserPopulation::ENHANCED_PROTECTION skipped_certificate_whitelist_);
: is_extended_reporting_
? ChromeUserPopulation::EXTENDED_REPORTING
: ChromeUserPopulation::SAFE_BROWSING;
request->mutable_population()->set_user_population(population);
request->mutable_population()->set_profile_management_status(
GetProfileManagementStatus(
g_browser_process->browser_policy_connector()));
request->mutable_population()->set_is_under_advanced_protection(
is_under_advanced_protection_);
request->mutable_population()->set_is_incognito(is_incognito_);
request->set_url(SanitizeUrl(source_url_));
request->set_skipped_url_whitelist(skipped_url_whitelist_);
request->set_skipped_certificate_whitelist(skipped_certificate_whitelist_);
request->set_locale(g_browser_process->GetApplicationLocale());
PopulateRequest(request.get());
if (request->referrer_chain_size() > 0 &&
type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE) {
SafeBrowsingNavigationObserverManager::SanitizeReferrerChain(
request->mutable_referrer_chain());
}
// TODO(mattm): fill out the remote IP addresses for tab resources. if (!client_download_request_->SerializeToString(
for (size_t i = 0; i < tab_redirects_.size(); ++i) { &client_download_request_data_)) {
ClientDownloadRequest::Resource* resource = request->add_resources();
DVLOG(2) << "tab redirect " << i << " " << tab_redirects_[i].spec();
resource->set_url(SanitizeUrl(tab_redirects_[i]));
resource->set_type(ClientDownloadRequest::TAB_REDIRECT);
}
if (tab_url_.is_valid()) {
ClientDownloadRequest::Resource* resource = request->add_resources();
resource->set_url(SanitizeUrl(tab_url_));
DVLOG(2) << "tab url " << resource->url();
resource->set_type(ClientDownloadRequest::TAB_URL);
if (tab_referrer_url_.is_valid()) {
resource->set_referrer(SanitizeUrl(tab_referrer_url_));
DVLOG(2) << "tab referrer " << resource->referrer();
}
}
request->set_file_basename(target_file_path_.BaseName().AsUTF8Unsafe());
request->set_download_type(type_);
#if defined(OS_MAC)
if (disk_image_signature_) {
request->set_udif_code_signature(disk_image_signature_->data(),
disk_image_signature_->size());
}
if (!detached_code_signatures_.empty()) {
request->mutable_detached_code_signature()->Swap(
&detached_code_signatures_);
}
#endif
if (archive_is_valid_ != FileAnalyzer::ArchiveValid::UNSET)
request->set_archive_valid(archive_is_valid_ ==
FileAnalyzer::ArchiveValid::VALID);
request->mutable_signature()->CopyFrom(signature_info_);
if (image_headers_)
request->set_allocated_image_headers(image_headers_.release());
if (!archived_binaries_.empty())
request->mutable_archived_binary()->Swap(&archived_binaries_);
request->set_archive_file_count(file_count_);
request->set_archive_directory_count(directory_count_);
request->set_request_ap_verdicts(is_under_advanced_protection_);
if (!request->SerializeToString(&client_download_request_data_)) {
FinishRequest(DownloadCheckResult::UNKNOWN, REASON_INVALID_REQUEST_PROTO); FinishRequest(DownloadCheckResult::UNKNOWN, REASON_INVALID_REQUEST_PROTO);
return; return;
} }
...@@ -563,16 +440,17 @@ void CheckClientDownloadRequestBase::SendRequest() { ...@@ -563,16 +440,17 @@ void CheckClientDownloadRequestBase::SendRequest() {
// This is checked just before the request is sent, to verify the request // This is checked just before the request is sent, to verify the request
// would have been sent. This emmulates the server returning a DANGEROUS // would have been sent. This emmulates the server returning a DANGEROUS
// verdict as closely as possible. // verdict as closely as possible.
if (IsDownloadManuallyBlacklisted(*request)) { if (IsDownloadManuallyBlacklisted(*client_download_request_)) {
DVLOG(1) << "Download verdict overridden to DANGEROUS by flag."; DVLOG(1) << "Download verdict overridden to DANGEROUS by flag.";
FinishRequest(DownloadCheckResult::DANGEROUS, REASON_MANUAL_BLACKLIST); FinishRequest(DownloadCheckResult::DANGEROUS, REASON_MANUAL_BLACKLIST);
return; return;
} }
NotifySendRequest(request.get()); NotifySendRequest(client_download_request_.get());
DVLOG(2) << "Sending a request for URL: " << source_url_; DVLOG(2) << "Sending a request for URL: " << source_url_;
DVLOG(2) << "Detected " << request->archived_binary().size() << " archived " DVLOG(2) << "Detected " << client_download_request_->archived_binary().size()
<< " archived "
<< "binaries (may be capped)"; << "binaries (may be capped)";
net::NetworkTrafficAnnotationTag traffic_annotation = net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("client_download_request", R"( net::DefineNetworkTrafficAnnotation("client_download_request", R"(
...@@ -640,20 +518,18 @@ void CheckClientDownloadRequestBase::SendRequest() { ...@@ -640,20 +518,18 @@ void CheckClientDownloadRequestBase::SendRequest() {
client_download_request_data_.size()); client_download_request_data_.size());
// Add the access token to the proto for display on chrome://safe-browsing // Add the access token to the proto for display on chrome://safe-browsing
request->set_access_token(access_token_); client_download_request_->set_access_token(access_token_);
// The following is to log this ClientDownloadRequest on any open // The following is to log this ClientDownloadRequest on any open
// chrome://safe-browsing pages. If no such page is open, the request is // chrome://safe-browsing pages. If no such page is open, the request is
// dropped and the |request| object deleted. // dropped and the |client_download_request_| object deleted.
content::GetUIThreadTaskRunner({})->PostTask( content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&WebUIInfoSingleton::AddToClientDownloadRequestsSent, base::BindOnce(&WebUIInfoSingleton::AddToClientDownloadRequestsSent,
base::Unretained(WebUIInfoSingleton::GetInstance()), base::Unretained(WebUIInfoSingleton::GetInstance()),
std::move(request))); std::move(client_download_request_)));
} }
// TODO: this method puts "DownloadProtectionService::" in front of a lot of
// stuff to avoid referencing the enums i copied to this .h file.
void CheckClientDownloadRequestBase::OnURLLoaderComplete( void CheckClientDownloadRequestBase::OnURLLoaderComplete(
std::unique_ptr<std::string> response_body) { std::unique_ptr<std::string> response_body) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -677,7 +553,7 @@ void CheckClientDownloadRequestBase::OnURLLoaderComplete( ...@@ -677,7 +553,7 @@ void CheckClientDownloadRequestBase::OnURLLoaderComplete(
if (!response.ParseFromString(*response_body.get())) { if (!response.ParseFromString(*response_body.get())) {
reason = REASON_INVALID_RESPONSE_PROTO; reason = REASON_INVALID_RESPONSE_PROTO;
result = DownloadCheckResult::UNKNOWN; result = DownloadCheckResult::UNKNOWN;
} else if (type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE) { } else if (sampled_unsupported_file_) {
// Ignore the verdict because we were just reporting a sampled file. // Ignore the verdict because we were just reporting a sampled file.
reason = REASON_SAMPLED_UNSUPPORTED_FILE; reason = REASON_SAMPLED_UNSUPPORTED_FILE;
result = DownloadCheckResult::UNKNOWN; result = DownloadCheckResult::UNKNOWN;
......
...@@ -19,10 +19,10 @@ ...@@ -19,10 +19,10 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/enterprise/connectors/common.h" #include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
#include "chrome/browser/safe_browsing/download_protection/download_request_maker.h"
#include "chrome/browser/safe_browsing/download_protection/file_analyzer.h" #include "chrome/browser/safe_browsing/download_protection/file_analyzer.h"
#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h"
#include "chrome/browser/safe_browsing/ui_manager.h" #include "chrome/browser/safe_browsing/ui_manager.h"
#include "chrome/common/safe_browsing/binary_feature_extractor.h"
#include "chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h" #include "chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h"
#include "chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h" #include "chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h"
#include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_service.h"
...@@ -44,24 +44,14 @@ namespace safe_browsing { ...@@ -44,24 +44,14 @@ namespace safe_browsing {
class CheckClientDownloadRequestBase { class CheckClientDownloadRequestBase {
public: public:
// URL and referrer of the window the download was started from.
struct TabUrls {
GURL url;
GURL referrer;
};
CheckClientDownloadRequestBase( CheckClientDownloadRequestBase(
GURL source_url, GURL source_url,
base::FilePath target_file_path, base::FilePath target_file_path,
base::FilePath full_path,
TabUrls tab_urls,
std::string mime_type,
std::string hash,
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
CheckDownloadCallback callback, CheckDownloadCallback callback,
DownloadProtectionService* service, DownloadProtectionService* service,
scoped_refptr<SafeBrowsingDatabaseManager> database_manager, scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor); std::unique_ptr<DownloadRequestMaker> download_request_maker);
virtual ~CheckClientDownloadRequestBase(); virtual ~CheckClientDownloadRequestBase();
void Start(); void Start();
...@@ -69,11 +59,6 @@ class CheckClientDownloadRequestBase { ...@@ -69,11 +59,6 @@ class CheckClientDownloadRequestBase {
DownloadProtectionService* service() const { return service_; } DownloadProtectionService* service() const { return service_; }
protected: protected:
// Prepares URLs to be put into a ping message. Currently this just shortens
// data: URIs, other URLs are included verbatim. If this is a sampled binary,
// we'll send a light-ping which strips PII from the URL.
std::string SanitizeUrl(const GURL& url) const;
// Subclasses can call this method to mark the request as finished (for // Subclasses can call this method to mark the request as finished (for
// example because the download was cancelled) before the safe browsing // example because the download was cancelled) before the safe browsing
// check has completed. This method can end up deleting |this|. // check has completed. This method can end up deleting |this|.
...@@ -89,30 +74,18 @@ class CheckClientDownloadRequestBase { ...@@ -89,30 +74,18 @@ class CheckClientDownloadRequestBase {
bool IsDownloadManuallyBlacklisted(const ClientDownloadRequest& request); bool IsDownloadManuallyBlacklisted(const ClientDownloadRequest& request);
void OnUrlWhitelistCheckDone(bool is_whitelisted); void OnUrlWhitelistCheckDone(bool is_whitelisted);
// Performs file feature extraction and SafeBrowsing ping for downloads that void OnRequestBuilt(std::unique_ptr<ClientDownloadRequest> request_proto);
// don't match the URL whitelist.
void AnalyzeFile();
void OnFileFeatureExtractionDone(FileAnalyzer::Results results);
void StartTimeout(); void StartTimeout();
void OnCertificateWhitelistCheckDone(bool is_whitelisted); void OnCertificateWhitelistCheckDone(bool is_whitelisted);
void GetTabRedirects();
void OnGotTabRedirects(history::RedirectList redirect_list);
void SendRequest(); void SendRequest();
void OnURLLoaderComplete(std::unique_ptr<std::string> response_body); void OnURLLoaderComplete(std::unique_ptr<std::string> response_body);
virtual bool IsSupportedDownload( virtual bool IsSupportedDownload(DownloadCheckResultReason* reason) = 0;
DownloadCheckResultReason* reason,
ClientDownloadRequest::DownloadType* type) = 0;
virtual content::BrowserContext* GetBrowserContext() const = 0; virtual content::BrowserContext* GetBrowserContext() const = 0;
virtual bool IsCancelled() = 0; virtual bool IsCancelled() = 0;
virtual base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() = 0; virtual base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() = 0;
// Called to populate any data in the request that is specific for the type of
// check being done. Most importantly this method is expected to set the hash
// and size of the download, add DOWNLOAD_URL and DOWNLOAD_REDIRECT
// resources to the request, and set the referrer chain.
virtual void PopulateRequest(ClientDownloadRequest* request) = 0;
// Called right before a network request is send to the server. // Called right before a network request is send to the server.
virtual void NotifySendRequest(const ClientDownloadRequest* request) = 0; virtual void NotifySendRequest(const ClientDownloadRequest* request) = 0;
...@@ -159,16 +132,14 @@ class CheckClientDownloadRequestBase { ...@@ -159,16 +132,14 @@ class CheckClientDownloadRequestBase {
// file being whitelisted by policy // file being whitelisted by policy
virtual bool IsWhitelistedByPolicy() const = 0; virtual bool IsWhitelistedByPolicy() const = 0;
// For sampled unsupported file types, replaces all URLs in
// |client_download_request_| with their origin.
void SanitizeRequest();
// Source URL being downloaded from. This shuold always be set, but could be // Source URL being downloaded from. This shuold always be set, but could be
// for example an artificial blob: URL if there is no source URL. // for example an artificial blob: URL if there is no source URL.
const GURL source_url_; const GURL source_url_;
const base::FilePath target_file_path_; const base::FilePath target_file_path_;
const base::FilePath full_path_;
// URL and referrer of the window the download was started from.
const GURL tab_url_;
const GURL tab_referrer_url_;
// URL chain of redirects leading to (but not including) |tab_url|.
std::vector<GURL> tab_redirects_;
CheckDownloadCallback callback_; CheckDownloadCallback callback_;
...@@ -178,52 +149,24 @@ class CheckClientDownloadRequestBase { ...@@ -178,52 +149,24 @@ class CheckClientDownloadRequestBase {
base::CancelableOnceClosure timeout_closure_; base::CancelableOnceClosure timeout_closure_;
std::unique_ptr<network::SimpleURLLoader> loader_; std::unique_ptr<network::SimpleURLLoader> loader_;
std::unique_ptr<ClientDownloadRequest> client_download_request_;
std::string client_download_request_data_; std::string client_download_request_data_;
bool archived_executable_ = false;
FileAnalyzer::ArchiveValid archive_is_valid_ =
FileAnalyzer::ArchiveValid::UNSET;
#if defined(OS_MAC)
std::unique_ptr<std::vector<uint8_t>> disk_image_signature_;
google::protobuf::RepeatedPtrField<
ClientDownloadRequest_DetachedCodeSignature>
detached_code_signatures_;
#endif
ClientDownloadRequest_SignatureInfo signature_info_;
std::unique_ptr<ClientDownloadRequest_ImageHeaders> image_headers_;
ArchivedBinaries archived_binaries_;
DownloadProtectionService* const service_; DownloadProtectionService* const service_;
const scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_;
const scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; const scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
const bool pingback_enabled_; const bool pingback_enabled_;
const std::unique_ptr<FileAnalyzer> file_analyzer_ =
std::make_unique<FileAnalyzer>(binary_feature_extractor_);
ClientDownloadRequest::DownloadType type_ =
ClientDownloadRequest::WIN_EXECUTABLE;
base::CancelableTaskTracker request_tracker_; // For HistoryService lookup. base::CancelableTaskTracker request_tracker_; // For HistoryService lookup.
base::TimeTicks start_time_ = base::TimeTicks::Now(); // Used for stats. base::TimeTicks start_time_ = base::TimeTicks::Now(); // Used for stats.
base::TimeTicks timeout_start_time_; base::TimeTicks timeout_start_time_;
base::TimeTicks request_start_time_; base::TimeTicks request_start_time_;
bool skipped_url_whitelist_ = false; bool skipped_url_whitelist_ = false;
bool skipped_certificate_whitelist_ = false; bool skipped_certificate_whitelist_ = false;
bool sampled_unsupported_file_ = false;
bool is_extended_reporting_ = false; bool is_extended_reporting_ = false;
bool is_incognito_ = false; bool is_incognito_ = false;
bool is_under_advanced_protection_ = false;
bool is_enhanced_protection_ = false; bool is_enhanced_protection_ = false;
int file_count_;
int directory_count_;
// The mime type of the download, if known.
std::string mime_type_;
// The hash of the download, if known.
std::string hash_;
// The token fetcher used to attach OAuth access tokens to requests for // The token fetcher used to attach OAuth access tokens to requests for
// appropriately consented users. // appropriately consented users.
std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher_; std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher_;
...@@ -231,6 +174,9 @@ class CheckClientDownloadRequestBase { ...@@ -231,6 +174,9 @@ class CheckClientDownloadRequestBase {
// The OAuth access token for the user profile, if needed in the request. // The OAuth access token for the user profile, if needed in the request.
std::string access_token_; std::string access_token_;
// Used to create the download request proto.
std::unique_ptr<DownloadRequestMaker> download_request_maker_;
DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequestBase); DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequestBase);
}; // namespace safe_browsing }; // namespace safe_browsing
......
...@@ -27,50 +27,22 @@ namespace safe_browsing { ...@@ -27,50 +27,22 @@ namespace safe_browsing {
using content::BrowserThread; using content::BrowserThread;
namespace {
GURL GetDownloadUrl(const GURL& frame_url) {
// Regular blob: URLs are of the form
// "blob:https://my-origin.com/def07373-cbd8-49d2-9ef7-20b071d34a1a". To make
// these URLs distinguishable from those we use a fixed string rather than a
// random UUID.
return GURL("blob:" + frame_url.GetOrigin().spec() +
"native-file-system-write");
}
CheckClientDownloadRequestBase::TabUrls TabUrlsFromWebContents(
content::WebContents* web_contents) {
CheckClientDownloadRequestBase::TabUrls result;
if (web_contents) {
content::NavigationEntry* entry =
web_contents->GetController().GetVisibleEntry();
if (entry) {
result.url = entry->GetURL();
result.referrer = entry->GetReferrer().url;
}
}
return result;
}
} // namespace
CheckNativeFileSystemWriteRequest::CheckNativeFileSystemWriteRequest( CheckNativeFileSystemWriteRequest::CheckNativeFileSystemWriteRequest(
std::unique_ptr<content::NativeFileSystemWriteItem> item, std::unique_ptr<content::NativeFileSystemWriteItem> item,
CheckDownloadCallback callback, CheckDownloadCallback callback,
DownloadProtectionService* service, DownloadProtectionService* service,
scoped_refptr<SafeBrowsingDatabaseManager> database_manager, scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor) scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor)
: CheckClientDownloadRequestBase(GetDownloadUrl(item->frame_url), : CheckClientDownloadRequestBase(
item->target_file_path, GetFileSystemAccessDownloadUrl(item->frame_url),
item->full_path, item->target_file_path,
TabUrlsFromWebContents(item->web_contents), item->browser_context,
"application/octet-stream", std::move(callback),
item->sha256_hash, service,
item->browser_context, std::move(database_manager),
std::move(callback), std::make_unique<DownloadRequestMaker>(binary_feature_extractor,
service, service,
std::move(database_manager), *item)),
std::move(binary_feature_extractor)),
item_(std::move(item)), item_(std::move(item)),
referrer_chain_data_(service->IdentifyReferrerChain(*item_)) { referrer_chain_data_(service->IdentifyReferrerChain(*item_)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -80,14 +52,12 @@ CheckNativeFileSystemWriteRequest ::~CheckNativeFileSystemWriteRequest() = ...@@ -80,14 +52,12 @@ CheckNativeFileSystemWriteRequest ::~CheckNativeFileSystemWriteRequest() =
default; default;
bool CheckNativeFileSystemWriteRequest::IsSupportedDownload( bool CheckNativeFileSystemWriteRequest::IsSupportedDownload(
DownloadCheckResultReason* reason, DownloadCheckResultReason* reason) {
ClientDownloadRequest::DownloadType* type) {
if (!FileTypePolicies::GetInstance()->IsCheckedBinaryFile( if (!FileTypePolicies::GetInstance()->IsCheckedBinaryFile(
item_->target_file_path)) { item_->target_file_path)) {
*reason = REASON_NOT_BINARY_FILE; *reason = REASON_NOT_BINARY_FILE;
return false; return false;
} }
*type = download_type_util::GetDownloadType(item_->target_file_path);
return true; return true;
} }
...@@ -100,33 +70,6 @@ bool CheckNativeFileSystemWriteRequest::IsCancelled() { ...@@ -100,33 +70,6 @@ bool CheckNativeFileSystemWriteRequest::IsCancelled() {
return false; return false;
} }
void CheckNativeFileSystemWriteRequest::PopulateRequest(
ClientDownloadRequest* request) {
request->mutable_digests()->set_sha256(item_->sha256_hash);
request->set_length(item_->size);
{
ClientDownloadRequest::Resource* resource = request->add_resources();
resource->set_url(SanitizeUrl(GetDownloadUrl(item_->frame_url)));
resource->set_type(ClientDownloadRequest::DOWNLOAD_URL);
if (item_->frame_url.is_valid())
resource->set_referrer(SanitizeUrl(item_->frame_url));
}
request->set_user_initiated(item_->has_user_gesture);
if (referrer_chain_data_ &&
!referrer_chain_data_->GetReferrerChain()->empty()) {
request->mutable_referrer_chain()->Swap(
referrer_chain_data_->GetReferrerChain());
request->mutable_referrer_chain_options()
->set_recent_navigations_to_collect(
referrer_chain_data_->recent_navigations_to_collect());
UMA_HISTOGRAM_COUNTS_100(
"SafeBrowsing.ReferrerURLChainSize.NativeFileSystemWriteAttribution",
referrer_chain_data_->referrer_chain_length());
}
}
base::WeakPtr<CheckClientDownloadRequestBase> base::WeakPtr<CheckClientDownloadRequestBase>
CheckNativeFileSystemWriteRequest::GetWeakPtr() { CheckNativeFileSystemWriteRequest::GetWeakPtr() {
return weakptr_factory_.GetWeakPtr(); return weakptr_factory_.GetWeakPtr();
...@@ -135,6 +78,9 @@ CheckNativeFileSystemWriteRequest::GetWeakPtr() { ...@@ -135,6 +78,9 @@ CheckNativeFileSystemWriteRequest::GetWeakPtr() {
void CheckNativeFileSystemWriteRequest::NotifySendRequest( void CheckNativeFileSystemWriteRequest::NotifySendRequest(
const ClientDownloadRequest* request) { const ClientDownloadRequest* request) {
service()->native_file_system_write_request_callbacks_.Notify(request); service()->native_file_system_write_request_callbacks_.Notify(request);
UMA_HISTOGRAM_COUNTS_100(
"SafeBrowsing.ReferrerURLChainSize.NativeFileSystemWriteAttribution",
request->referrer_chain().size());
} }
void CheckNativeFileSystemWriteRequest::SetDownloadPingToken( void CheckNativeFileSystemWriteRequest::SetDownloadPingToken(
......
...@@ -36,11 +36,9 @@ class CheckNativeFileSystemWriteRequest ...@@ -36,11 +36,9 @@ class CheckNativeFileSystemWriteRequest
private: private:
// CheckClientDownloadRequestBase overrides: // CheckClientDownloadRequestBase overrides:
bool IsSupportedDownload(DownloadCheckResultReason* reason, bool IsSupportedDownload(DownloadCheckResultReason* reason) override;
ClientDownloadRequest::DownloadType* type) override;
content::BrowserContext* GetBrowserContext() const override; content::BrowserContext* GetBrowserContext() const override;
bool IsCancelled() override; bool IsCancelled() override;
void PopulateRequest(ClientDownloadRequest* request) override;
base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() override; base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() override;
void NotifySendRequest(const ClientDownloadRequest* request) override; void NotifySendRequest(const ClientDownloadRequest* request) override;
......
...@@ -27,10 +27,12 @@ ...@@ -27,10 +27,12 @@
#include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h" #include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h"
#include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h" #include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
#include "chrome/browser/safe_browsing/download_protection/download_request_maker.h"
#include "chrome/browser/safe_browsing/download_protection/download_url_sb_client.h" #include "chrome/browser/safe_browsing/download_protection/download_url_sb_client.h"
#include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h" #include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h"
#include "chrome/browser/safe_browsing/services_delegate.h" #include "chrome/browser/safe_browsing/services_delegate.h"
#include "chrome/common/safe_browsing/binary_feature_extractor.h" #include "chrome/common/safe_browsing/binary_feature_extractor.h"
#include "chrome/common/safe_browsing/download_type_util.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "components/download/public/common/download_item.h" #include "components/download/public/common/download_item.h"
#include "components/google/core/common/google_util.h" #include "components/google/core/common/google_util.h"
...@@ -238,13 +240,12 @@ bool DownloadProtectionService::IsSupportedDownload( ...@@ -238,13 +240,12 @@ bool DownloadProtectionService::IsSupportedDownload(
const download::DownloadItem& item, const download::DownloadItem& item,
const base::FilePath& target_path) const { const base::FilePath& target_path) const {
DownloadCheckResultReason reason = REASON_MAX; DownloadCheckResultReason reason = REASON_MAX;
ClientDownloadRequest::DownloadType type =
ClientDownloadRequest::WIN_EXECUTABLE;
// TODO(nparker): Remove the CRX check here once can support // TODO(nparker): Remove the CRX check here once can support
// UNKNOWN types properly. http://crbug.com/581044 // UNKNOWN types properly. http://crbug.com/581044
return (CheckClientDownloadRequest::IsSupportedDownload(item, target_path, return (CheckClientDownloadRequest::IsSupportedDownload(item, target_path,
&reason, &type) && &reason) &&
(ClientDownloadRequest::CHROME_EXTENSION != type)); download_type_util::GetDownloadType(target_path) !=
ClientDownloadRequest::CHROME_EXTENSION);
} }
void DownloadProtectionService::CheckPPAPIDownloadRequest( void DownloadProtectionService::CheckPPAPIDownloadRequest(
......
...@@ -58,6 +58,7 @@ class CheckClientDownloadRequest; ...@@ -58,6 +58,7 @@ class CheckClientDownloadRequest;
class CheckClientDownloadRequestBase; class CheckClientDownloadRequestBase;
class CheckNativeFileSystemWriteRequest; class CheckNativeFileSystemWriteRequest;
class ClientDownloadRequest; class ClientDownloadRequest;
class DownloadRequestMaker;
class DownloadFeedbackService; class DownloadFeedbackService;
class PPAPIDownloadRequest; class PPAPIDownloadRequest;
...@@ -213,6 +214,7 @@ class DownloadProtectionService { ...@@ -213,6 +214,7 @@ class DownloadProtectionService {
friend class CheckClientDownloadRequest; friend class CheckClientDownloadRequest;
friend class CheckNativeFileSystemWriteRequest; friend class CheckNativeFileSystemWriteRequest;
friend class DeepScanningRequest; friend class DeepScanningRequest;
friend class DownloadRequestMaker;
FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest, FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
TestDownloadRequestTimeout); TestDownloadRequestTimeout);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "net/cert/x509_util.h" #include "net/cert/x509_util.h"
#include "url/gurl.h"
namespace safe_browsing { namespace safe_browsing {
...@@ -92,4 +93,13 @@ void GetCertificateWhitelistStrings( ...@@ -92,4 +93,13 @@ void GetCertificateWhitelistStrings(
} }
} }
GURL GetFileSystemAccessDownloadUrl(const GURL& frame_url) {
// Regular blob: URLs are of the form
// "blob:https://my-origin.com/def07373-cbd8-49d2-9ef7-20b071d34a1a". To make
// these URLs distinguishable from those we use a fixed string rather than a
// random UUID.
return GURL("blob:" + frame_url.GetOrigin().spec() +
"native-file-system-write");
}
} // namespace safe_browsing } // namespace safe_browsing
...@@ -143,6 +143,8 @@ void GetCertificateWhitelistStrings( ...@@ -143,6 +143,8 @@ void GetCertificateWhitelistStrings(
const net::X509Certificate& issuer, const net::X509Certificate& issuer,
std::vector<std::string>* whitelist_strings); std::vector<std::string>* whitelist_strings);
GURL GetFileSystemAccessDownloadUrl(const GURL& frame_url);
} // namespace safe_browsing } // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_PROTECTION_UTIL_H_ #endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_PROTECTION_UTIL_H_
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/download_protection/download_request_maker.h"
#include <memory>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h"
#include "components/safe_browsing/core/common/utils.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
namespace safe_browsing {
namespace {
DownloadRequestMaker::TabUrls TabUrlsFromWebContents(
content::WebContents* web_contents) {
DownloadRequestMaker::TabUrls result;
if (web_contents) {
content::NavigationEntry* entry =
web_contents->GetController().GetVisibleEntry();
if (entry) {
result.url = entry->GetURL();
result.referrer = entry->GetReferrer().url;
}
}
return result;
}
} // namespace
DownloadRequestMaker::DownloadRequestMaker(
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
download::DownloadItem* item)
: browser_context_(content::DownloadItemUtils::GetBrowserContext(item)),
request_(std::make_unique<ClientDownloadRequest>()),
binary_feature_extractor_(binary_feature_extractor),
tab_urls_({item->GetTabUrl(), item->GetTabReferrerUrl()}),
target_file_path_(item->GetTargetFilePath()),
full_path_(item->GetFullPath()) {
request_->set_url(ShortURLForReporting(item->GetURL()));
request_->mutable_digests()->set_sha256(item->GetHash());
request_->set_length(item->GetReceivedBytes());
for (size_t i = 0; i < item->GetUrlChain().size(); ++i) {
ClientDownloadRequest::Resource* resource = request_->add_resources();
resource->set_url(ShortURLForReporting(item->GetUrlChain()[i]));
if (i == item->GetUrlChain().size() - 1) {
// The last URL in the chain is the download URL.
resource->set_type(ClientDownloadRequest::DOWNLOAD_URL);
resource->set_referrer(ShortURLForReporting(item->GetReferrerUrl()));
DVLOG(2) << "dl url " << resource->url();
if (!item->GetRemoteAddress().empty()) {
resource->set_remote_ip(item->GetRemoteAddress());
DVLOG(2) << " dl url remote addr: " << resource->remote_ip();
}
DVLOG(2) << "dl referrer " << resource->referrer();
} else {
DVLOG(2) << "dl redirect " << i << " " << resource->url();
resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT);
}
}
request_->set_user_initiated(item->HasUserGesture());
auto* referrer_chain_data = static_cast<ReferrerChainData*>(
item->GetUserData(ReferrerChainData::kDownloadReferrerChainDataKey));
if (referrer_chain_data &&
!referrer_chain_data->GetReferrerChain()->empty()) {
request_->mutable_referrer_chain()->Swap(
referrer_chain_data->GetReferrerChain());
request_->mutable_referrer_chain_options()
->set_recent_navigations_to_collect(
referrer_chain_data->recent_navigations_to_collect());
}
}
DownloadRequestMaker::DownloadRequestMaker(
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
DownloadProtectionService* service,
const content::NativeFileSystemWriteItem& item)
: browser_context_(item.browser_context),
request_(std::make_unique<ClientDownloadRequest>()),
binary_feature_extractor_(binary_feature_extractor),
tab_urls_(TabUrlsFromWebContents(item.web_contents)),
target_file_path_(item.target_file_path),
full_path_(item.full_path) {
request_->set_url(
ShortURLForReporting(GetFileSystemAccessDownloadUrl(item.frame_url)));
request_->mutable_digests()->set_sha256(item.sha256_hash);
request_->set_length(item.size);
{
ClientDownloadRequest::Resource* resource = request_->add_resources();
resource->set_url(
ShortURLForReporting(GetFileSystemAccessDownloadUrl(item.frame_url)));
resource->set_type(ClientDownloadRequest::DOWNLOAD_URL);
if (item.frame_url.is_valid())
resource->set_referrer(ShortURLForReporting(item.frame_url));
}
request_->set_user_initiated(item.has_user_gesture);
std::unique_ptr<ReferrerChainData> referrer_chain_data =
service->IdentifyReferrerChain(item);
if (referrer_chain_data &&
!referrer_chain_data->GetReferrerChain()->empty()) {
request_->mutable_referrer_chain()->Swap(
referrer_chain_data->GetReferrerChain());
request_->mutable_referrer_chain_options()
->set_recent_navigations_to_collect(
referrer_chain_data->recent_navigations_to_collect());
}
}
DownloadRequestMaker::~DownloadRequestMaker() = default;
void DownloadRequestMaker::Start(DownloadRequestMaker::Callback callback) {
callback_ = std::move(callback);
Profile* profile = Profile::FromBrowserContext(browser_context_);
bool is_extended_reporting =
profile && IsExtendedReportingEnabled(*profile->GetPrefs());
bool is_incognito = browser_context_ && browser_context_->IsOffTheRecord();
bool is_under_advanced_protection =
profile && AdvancedProtectionStatusManagerFactory::GetForProfile(profile)
->IsUnderAdvancedProtection();
bool is_enhanced_protection =
profile && IsEnhancedProtectionEnabled(*profile->GetPrefs());
auto population = is_enhanced_protection
? ChromeUserPopulation::ENHANCED_PROTECTION
: is_extended_reporting
? ChromeUserPopulation::EXTENDED_REPORTING
: ChromeUserPopulation::SAFE_BROWSING;
request_->mutable_population()->set_user_population(population);
request_->mutable_population()->set_profile_management_status(
GetProfileManagementStatus(
g_browser_process->browser_policy_connector()));
request_->mutable_population()->set_is_under_advanced_protection(
is_under_advanced_protection);
request_->mutable_population()->set_is_incognito(is_incognito);
request_->set_request_ap_verdicts(is_under_advanced_protection);
request_->set_locale(g_browser_process->GetApplicationLocale());
request_->set_file_basename(target_file_path_.BaseName().AsUTF8Unsafe());
file_analyzer_->Start(
target_file_path_, full_path_,
base::BindOnce(&DownloadRequestMaker::OnFileFeatureExtractionDone,
weakptr_factory_.GetWeakPtr()));
}
void DownloadRequestMaker::OnFileFeatureExtractionDone(
FileAnalyzer::Results results) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
request_->set_download_type(results.type);
if (results.archive_is_valid != FileAnalyzer::ArchiveValid::UNSET)
request_->set_archive_valid(results.archive_is_valid ==
FileAnalyzer::ArchiveValid::VALID);
request_->mutable_archived_binary()->CopyFrom(results.archived_binaries);
request_->mutable_signature()->CopyFrom(results.signature_info);
request_->mutable_image_headers()->CopyFrom(results.image_headers);
request_->set_archive_file_count(results.file_count);
request_->set_archive_directory_count(results.directory_count);
#if defined(OS_MAC)
if (!results.disk_image_signature.empty()) {
request_->set_udif_code_signature(results.disk_image_signature.data(),
results.disk_image_signature.size());
}
if (!results.detached_code_signatures.empty()) {
request_->mutable_detached_code_signature()->CopyFrom(
results.detached_code_signatures);
}
#endif
GetTabRedirects();
}
void DownloadRequestMaker::GetTabRedirects() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!tab_urls_.url.is_valid()) {
OnGotTabRedirects({});
return;
}
Profile* profile = Profile::FromBrowserContext(browser_context_);
history::HistoryService* history = HistoryServiceFactory::GetForProfile(
profile, ServiceAccessType::EXPLICIT_ACCESS);
if (!history) {
OnGotTabRedirects({});
return;
}
history->QueryRedirectsTo(
tab_urls_.url,
base::BindOnce(&DownloadRequestMaker::OnGotTabRedirects,
weakptr_factory_.GetWeakPtr()),
&request_tracker_);
}
void DownloadRequestMaker::OnGotTabRedirects(
history::RedirectList redirect_list) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (size_t i = 0; i < redirect_list.size(); ++i) {
ClientDownloadRequest::Resource* resource = request_->add_resources();
DVLOG(2) << "tab redirect " << i << " " << redirect_list[i].spec();
resource->set_url(ShortURLForReporting(redirect_list[i]));
resource->set_type(ClientDownloadRequest::TAB_REDIRECT);
}
if (tab_urls_.url.is_valid()) {
ClientDownloadRequest::Resource* resource = request_->add_resources();
resource->set_url(ShortURLForReporting(tab_urls_.url));
DVLOG(2) << "tab url " << resource->url();
resource->set_type(ClientDownloadRequest::TAB_URL);
if (tab_urls_.referrer.is_valid()) {
resource->set_referrer(ShortURLForReporting(tab_urls_.referrer));
DVLOG(2) << "tab referrer " << resource->referrer();
}
}
std::move(callback_).Run(std::move(request_));
}
} // namespace safe_browsing
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_REQUEST_MAKER_H_
#define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_REQUEST_MAKER_H_
#include <memory>
#include "base/callback.h"
#include "chrome/browser/safe_browsing/download_protection/file_analyzer.h"
#include "components/download/public/common/download_item.h"
#include "components/history/core/browser/history_service.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
#include "content/public/browser/native_file_system_write_item.h"
namespace safe_browsing {
class DownloadProtectionService;
// This class encapsulate the process of populating all the fields in a Safe
// Browsing download ping.
class DownloadRequestMaker {
public:
using Callback =
base::OnceCallback<void(std::unique_ptr<ClientDownloadRequest>)>;
// URL and referrer of the window the download was started from.
struct TabUrls {
GURL url;
GURL referrer;
};
DownloadRequestMaker(
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
download::DownloadItem* item);
DownloadRequestMaker(
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
DownloadProtectionService* service,
const content::NativeFileSystemWriteItem& item);
~DownloadRequestMaker();
// Starts filling in fields in the download ping. Will run the callback with
// the fully-populated ping.
void Start(Callback callback);
private:
// Callback when |file_analyzer_| is done analyzing the download.
void OnFileFeatureExtractionDone(FileAnalyzer::Results results);
// Helper function to get the tab redirects from the history service.
void GetTabRedirects();
// Callback when the history service has retrieved the tab redirects.
void OnGotTabRedirects(history::RedirectList redirect_list);
content::BrowserContext* browser_context_;
std::unique_ptr<ClientDownloadRequest> request_;
const scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_;
const std::unique_ptr<FileAnalyzer> file_analyzer_ =
std::make_unique<FileAnalyzer>(binary_feature_extractor_);
base::CancelableTaskTracker request_tracker_; // For HistoryService lookup.
// The current URL for the WebContents that initiated the download, and its
// referrer.
TabUrls tab_urls_;
// The ultimate destination for the download.
const base::FilePath target_file_path_;
// The current path to the file contents.
const base::FilePath full_path_;
Callback callback_;
base::WeakPtrFactory<DownloadRequestMaker> weakptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DownloadRequestMaker);
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_REQUEST_MAKER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment