blob: 5da34a192d2e50fd805ed7b5ea358628f90b4348 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Helper class which handles communication with the SafeBrowsing servers for
// improved binary download protection.
#ifndef CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_PROTECTION_SERVICE_H_
#define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_PROTECTION_SERVICE_H_
#include <stdint.h>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback_list.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
#include "base/types/optional_ref.h"
#include "chrome/browser/download/download_commands.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_delegate.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_observer.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
#include "chrome/browser/safe_browsing/services_delegate.h"
#include "components/safe_browsing/core/browser/db/database_manager.h"
#include "components/safe_browsing/core/browser/safe_browsing_metrics_collector.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "components/sessions/core/session_id.h"
#include "url/gurl.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h"
#endif
namespace content {
class PageNavigator;
struct FileSystemAccessWriteItem;
} // namespace content
namespace download {
class DownloadItem;
}
namespace network {
class SharedURLLoaderFactory;
}
class Profile;
namespace safe_browsing {
class BinaryFeatureExtractor;
class CheckClientDownloadRequest;
class CheckClientDownloadRequestBase;
class CheckFileSystemAccessWriteRequest;
class ClientDownloadRequest;
class DeepScanningRequest;
class DownloadRequestMaker;
class SafeBrowsingUIManager;
#if !BUILDFLAG(IS_ANDROID)
class DownloadFeedbackService;
#endif
// This class provides an asynchronous API to check whether a particular
// client download is malicious or not.
class DownloadProtectionService {
public:
// Creates a download service. The service is initially disabled. You need
// to call SetEnabled() to start it. `sb_service` owns this object via the
// ServicesDelegate. `delegate` must not be null.
DownloadProtectionService(
SafeBrowsingServiceImpl* sb_service,
std::unique_ptr<DownloadProtectionDelegate> delegate);
// Same as above, but creates the default delegate instance. This is meant as
// a convenience for tests. Prefer the constructor above that explicitly
// provides the delegate, if possible.
explicit DownloadProtectionService(SafeBrowsingServiceImpl* sb_service);
DownloadProtectionService(const DownloadProtectionService&) = delete;
DownloadProtectionService& operator=(const DownloadProtectionService&) =
delete;
virtual ~DownloadProtectionService();
// Parse a flag of blocklisted sha256 hashes to check at each download.
// This is used for testing, to hunt for safe-browsing by-pass bugs.
virtual void ParseManualBlocklistFlag();
// Return true if this hash value is blocklisted via flag (for testing).
virtual bool IsHashManuallyBlocklisted(const std::string& sha256_hash) const;
// Checks whether the given client download is likely to be malicious or not.
// The result is delivered asynchronously via the given callback. This
// method must be called on the UI thread, and the callback will also be
// invoked on the UI thread. This method must be called once the download
// is finished and written to disk.
virtual void CheckClientDownload(
download::DownloadItem* item,
CheckDownloadRepeatingCallback callback,
base::optional_ref<const std::string> password = std::nullopt);
// Checks the user permissions, then calls |CheckClientDownload| if
// appropriate. Returns whether we may do more asynchronous work to check the
// download, such as sending a ping (potentially subject to sampling or other
// eligibility checks). If this returns true, the `callback` will be invoked
// with the result of a check. If this returns false, the `callback` will not
// be run.
virtual bool MaybeCheckClientDownload(
download::DownloadItem* item,
CheckDownloadRepeatingCallback callback);
// Cancel the pending check for `item`. This function simply drops the pending
// work in the `DownloadProtectionService`. The caller is responsible for
// updating the download state so that it completes successfully.
void CancelChecksForDownload(download::DownloadItem* item);
// Returns whether the download URL should be checked for safety based on user
// prefs.
virtual bool ShouldCheckDownloadUrl(download::DownloadItem* item);
// Checks whether any of the URLs in the redirect chain of the
// download match the SafeBrowsing bad binary URL list. The result is
// delivered asynchronously via the given callback. This method must be
// called on the UI thread, and the callback will also be invoked on the UI
// thread. Pre-condition: !info.download_url_chain.empty().
// The caller should check ShouldCheckDownloadUrl() beforehand; this is not
// verified in this method.
virtual void CheckDownloadUrl(download::DownloadItem* item,
CheckDownloadCallback callback);
// Returns true if the download specified by |info| may be scanned by
// CheckClientDownload() for malicious content. (Caller may apply further
// logic to determine if a scan occurs, such as sampling or other checks.)
// May modify the DownloadItem with a SupportsUserData::Data.
virtual bool IsSupportedDownload(download::DownloadItem& item,
const base::FilePath& target_path) const;
// If download protection is enabled for `item`, checks whether the given File
// System Access write operation is likely to be malicious or not. The result
// of the check is delivered asynchronously via the given callback, or the
// callback will be invoked with a result of UNKNOWN. This method must be
// called on the UI thread, and the callback will also be invoked on the UI
// thread. This method must be called once the write is finished and data has
// been written to disk.
virtual void CheckFileSystemAccessWrite(
std::unique_ptr<content::FileSystemAccessWriteItem> item,
CheckDownloadCallback callback);
// Display more information to the user regarding the download specified by
// |info|. This method is invoked when the user requests more information
// about a download that was marked as malicious.
void ShowDetailsForDownload(const download::DownloadItem* item,
content::PageNavigator* navigator);
// Enables or disables the service. This is usually called by the
// SafeBrowsingServiceImpl, which tracks whether any profile uses these
// services at all. Disabling causes any pending and future requests to have
// their callbacks called with "UNKNOWN" results.
void SetEnabled(bool enabled);
bool enabled() const { return enabled_; }
DownloadProtectionDelegate* delegate() { return delegate_.get(); }
const DownloadProtectionDelegate* delegate() const { return delegate_.get(); }
// Returns the URL that will be contacted for download protection requests.
const GURL& GetDownloadRequestUrl() const;
// Returns the timeout that is used by CheckClientDownload().
base::TimeDelta GetDownloadRequestTimeout() const;
// Checks the user permissions, and submits the downloaded file if
// appropriate. Returns whether the submission was successful.
bool MaybeBeginFeedbackForDownload(Profile* profile,
download::DownloadItem* download,
const std::string& ping_request,
const std::string& ping_response);
// Registers a callback that will be run when a ClientDownloadRequest has
// been formed.
base::CallbackListSubscription RegisterClientDownloadRequestCallback(
const ClientDownloadRequestCallback& callback);
// Registers a callback that will be run when a FileSystemAccessWriteRequest
// has been formed.
base::CallbackListSubscription RegisterFileSystemAccessWriteRequestCallback(
const FileSystemAccessWriteRequestCallback& callback);
double allowlist_sample_rate() const;
static void SetDownloadProtectionData(
download::DownloadItem* item,
const std::string& token,
const ClientDownloadResponse::Verdict& verdict,
const ClientDownloadResponse::TailoredVerdict& tailored_verdict);
static std::string GetDownloadPingToken(const download::DownloadItem* item);
// Whether a DownloadProtectionData is found on the item.
static bool HasDownloadProtectionVerdict(const download::DownloadItem* item);
// Returns ClientDownloadResponse::SAFE by default if no
// DownloadProtectionData is found.
static ClientDownloadResponse::Verdict GetDownloadProtectionVerdict(
const download::DownloadItem* item);
static ClientDownloadResponse::TailoredVerdict
GetDownloadProtectionTailoredVerdict(const download::DownloadItem* item);
// Sends dangerous download opened report when download is opened or
// shown in folder.
void MaybeSendDangerousDownloadOpenedReport(download::DownloadItem* item,
bool show_download_in_folder);
// Called to trigger a bypass event report for |download|. This is used when
// the async scan verdict is received for a file that was already opened by
// the user while it was being processed, and the verdict ended up being
// "dangerous" or "sensitive".
void ReportDelayedBypassEvent(download::DownloadItem* download,
download::DownloadDangerType danger_type);
#if !BUILDFLAG(IS_ANDROID)
// Uploads `metadata` to Safe Browsing for deep scanning, using the upload
// service attached to the profile `item` was downloaded in. This is
// non-blocking, and the result we be provided through `callback`. `trigger`
// is used to identify the reason for deep scanning, aka enterprise policy or
// APP. `download_check_result` indicates the previously known SB verdict to
// apply to the download should deep scanning fail. `analysis_settings`
// contains settings to apply throughout scanning (types of scans to do,
// whether to block/allow large files, etc). This must be called on the UI
// thread.
void UploadForDeepScanning(
std::unique_ptr<DeepScanningMetadata> metadata,
CheckDownloadRepeatingCallback callback,
DownloadItemWarningData::DeepScanTrigger trigger,
DownloadCheckResult download_check_result,
enterprise_connectors::AnalysisSettings analysis_settings,
base::optional_ref<const std::string> password);
// Helper functions for encrypted archive scans.
static void UploadForConsumerDeepScanning(
download::DownloadItem* item,
DownloadItemWarningData::DeepScanTrigger trigger,
base::optional_ref<const std::string> password);
static void CheckDownloadWithLocalDecryption(
download::DownloadItem* item,
base::optional_ref<const std::string> password);
// Uploads a save package `item` for deep scanning. `save_package_file`
// contains a mapping of on-disk files part of that save package to their
// final paths.
void UploadSavePackageForDeepScanning(
download::DownloadItem* item,
base::flat_map<base::FilePath, base::FilePath> save_package_files,
CheckDownloadRepeatingCallback callback,
enterprise_connectors::AnalysisSettings analysis_settings);
// Returns all the currently active deep scanning requests.
std::vector<DeepScanningRequest*> GetDeepScanningRequests();
#endif // !BUILDFLAG(IS_ANDROID)
virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
content::BrowserContext* browser_context);
// Removes all pending download requests that are associated with the
// `browser_context`.
void RemovePendingDownloadRequests(content::BrowserContext* browser_context);
// Returns the maximum number of user gestures for a download referrer
// chain. If `item` is non-null, information about that download may
// change the limit.
static int GetDownloadAttributionUserGestureLimit(
download::DownloadItem* item = nullptr);
private:
friend class DownloadUrlSBClient;
template <bool UseMockDbManager>
friend class DownloadProtectionServiceTestBase;
friend class DownloadDangerPromptTest;
friend class CheckClientDownloadRequestBase;
friend class CheckClientDownloadRequest;
friend class CheckFileSystemAccessWriteRequest;
friend class DownloadRequestMaker;
#if !BUILDFLAG(IS_ANDROID)
friend class DeepScanningRequest;
#endif
FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceMockTimeTest,
TestDownloadRequestTimeout);
FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
VerifyReferrerChainWithEmptyNavigationHistory);
FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
VerifyReferrerChainLengthForExtendedReporting);
static const void* const kDownloadProtectionDataKey;
// Helper class for easy setting and getting data related to download
// protection. The data is only set when the server returns an unsafe verdict
// (i.e. not safe or unknown).
class DownloadProtectionData : public base::SupportsUserData::Data {
public:
explicit DownloadProtectionData(
const std::string& token,
const ClientDownloadResponse::Verdict& verdict,
const ClientDownloadResponse::TailoredVerdict& tailored_verdict)
: token_string_(token),
verdict_(verdict),
tailored_verdict_(tailored_verdict) {}
DownloadProtectionData(const DownloadProtectionData&) = delete;
DownloadProtectionData& operator=(const DownloadProtectionData&) = delete;
std::string token_string() { return token_string_; }
ClientDownloadResponse::Verdict verdict() { return verdict_; }
ClientDownloadResponse::TailoredVerdict tailored_verdict() {
return tailored_verdict_;
}
private:
std::string token_string_;
ClientDownloadResponse::Verdict verdict_;
ClientDownloadResponse::TailoredVerdict tailored_verdict_;
};
// Cancels all requests in |download_requests_|, and empties it, releasing
// the references to the requests.
void CancelPendingRequests();
// Called by a CheckClientDownloadRequest instance when it finishes, to
// remove it from |download_requests_| and to report security sensitive
// events to safe_browsing_metrics_collector.
void RequestFinished(CheckClientDownloadRequestBase* request,
content::BrowserContext* browser_context,
DownloadCheckResult result);
#if !BUILDFLAG(IS_ANDROID)
// Called by a DeepScanningRequest when it finishes, to remove it from
// |deep_scanning_requests_|.
virtual void RequestFinished(DeepScanningRequest* request);
#endif
// Routes the dangerous download opened reports to `SafeBrowsingEventRouter`
// and `ReportingEventRouter`, if available.
void OnDangerousDownloadOpened(download::DownloadItem* item,
Profile* profile);
// Sends sensitive file bypassed event via `ReportingEventRouter`.
void ReportSensitiveFileBypassEnterpriseEvent(
download::DownloadItem* item,
Profile* profile,
const enterprise_connectors::FileMetadata& metadata,
const enterprise_connectors::ContentAnalysisResponse::Result& result,
const google::protobuf::RepeatedPtrField<ReferrerChainEntry>&
referrer_chain,
const google::protobuf::RepeatedPtrField<std::string>& frame_urls);
// Sends dangerous download opened event via `ReportingEventRouter`.
void ReportDangerousDownloadOpenedEnterpriseEvent(
download::DownloadItem* item,
Profile* profile,
const enterprise_connectors::FileMetadata& metadata,
const google::protobuf::RepeatedPtrField<ReferrerChainEntry>&
referrer_chain,
const google::protobuf::RepeatedPtrField<std::string>& frame_urls);
void ReportDangerousDownloadOpenedEnterpriseEvent(
download::DownloadItem* item,
Profile* profile,
const google::protobuf::RepeatedPtrField<ReferrerChainEntry>&
referrer_chain,
const google::protobuf::RepeatedPtrField<std::string>& frame_urls);
// Sends dangerous download opened event via `SafeBrowsingPrivateEventRouter`.
void ReportDangerousDownloadOpenedSafeBrowsingEvent(
download::DownloadItem* item,
Profile* profile,
const enterprise_connectors::FileMetadata& metadata);
void ReportDangerousDownloadOpenedSafeBrowsingEvent(
download::DownloadItem* item,
Profile* profile);
#if !BUILDFLAG(IS_ANDROID)
// Get the BinaryUploadService for the given |profile|. Virtual so it can be
// overridden in tests.
virtual BinaryUploadService* GetBinaryUploadService(
Profile* profile,
const enterprise_connectors::AnalysisSettings& settings);
#endif
// Callback when deep scanning has finished, but we may want to do the
// metadata check anyway.
void MaybeCheckMetadataAfterDeepScanning(
download::DownloadItem* item,
CheckDownloadRepeatingCallback callback,
DownloadCheckResult result);
raw_ptr<SafeBrowsingServiceImpl> sb_service_ = nullptr;
// Delegate providing platform-specific logic. Never null.
std::unique_ptr<DownloadProtectionDelegate> delegate_;
// These pointers may be NULL if SafeBrowsing is disabled.
scoped_refptr<SafeBrowsingUIManager> ui_manager_;
scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
// Set of pending server requests for DownloadManager mediated downloads.
base::flat_map<
content::BrowserContext*,
base::flat_map<CheckClientDownloadRequestBase*,
std::unique_ptr<CheckClientDownloadRequestBase>>>
context_download_requests_;
#if !BUILDFLAG(IS_ANDROID)
// Set of pending server requests for deep scanning.
base::flat_set<std::unique_ptr<DeepScanningRequest>> deep_scanning_requests_;
#endif
// Keeps track of the state of the service.
bool enabled_ = false;
// BinaryFeatureExtractor object, may be overridden for testing.
scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_;
#if !BUILDFLAG(IS_ANDROID)
std::unique_ptr<DownloadFeedbackService> feedback_service_;
#endif
// A list of callbacks to be run on the main thread when a
// ClientDownloadRequest has been formed.
ClientDownloadRequestCallbackList client_download_request_callbacks_;
// A list of callbacks to be run on the main thread when a
// FileSystemAccessWriteRequest has been formed.
FileSystemAccessWriteRequestCallbackList
file_system_access_write_request_callbacks_;
// List of 8-byte hashes that are blocklisted manually by flag.
// Normally empty.
std::set<std::string> manual_blocklist_hashes_;
// Rate of allowlisted downloads we sample to send out download ping.
// Overrides the value provided by the delegate. Intended for testing only.
std::optional<double> allowlist_sample_rate_;
// DownloadProtectionObserver to send real time reports for dangerous download
// events and handle special user actions on the download.
DownloadProtectionObserver download_protection_observer_;
base::WeakPtrFactory<DownloadProtectionService> weak_ptr_factory_;
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_PROTECTION_SERVICE_H_