1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/safe_browsing/download_protection/download_reporter.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/download/simple_download_manager_coordinator_factory.h"
10 #include "chrome/browser/enterprise/connectors/common.h"
11 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
12 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
13 #include "chrome/browser/profiles/profile_key.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
16 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
17 #include "components/download/public/common/download_danger_type.h"
18 #include "components/download/public/common/download_item.h"
19 #include "components/download/public/common/simple_download_manager_coordinator.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/download_item_utils.h"
22
23 namespace safe_browsing {
24
25 namespace {
26
DangerTypeIsDangerous(download::DownloadDangerType danger_type)27 bool DangerTypeIsDangerous(download::DownloadDangerType danger_type) {
28 return (danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
29 danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
30 danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
31 danger_type == download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
32 danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
33 danger_type == download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
34 }
35
DangerTypeToThreatType(download::DownloadDangerType danger_type)36 std::string DangerTypeToThreatType(download::DownloadDangerType danger_type) {
37 switch (danger_type) {
38 case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
39 return "DANGEROUS_FILE_TYPE";
40 case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
41 return "DANGEROUS_URL";
42 case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
43 return "DANGEROUS";
44 case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
45 return "UNCOMMON";
46 case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
47 return "DANGEROUS_HOST";
48 case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
49 return "POTENTIALLY_UNWANTED";
50 default:
51 // Expects to only be called with the dangerous threat types listed above.
52 NOTREACHED() << "Unexpected danger type: " << danger_type;
53 return "UNKNOWN";
54 }
55 }
56
MaybeReportDangerousDownloadWarning(download::DownloadItem * download)57 void MaybeReportDangerousDownloadWarning(download::DownloadItem* download) {
58 // If |download| has a deep scanning malware verdict, then it means the
59 // dangerous file has already been reported.
60 auto* scan_result = static_cast<enterprise_connectors::ScanResult*>(
61 download->GetUserData(enterprise_connectors::ScanResult::kKey));
62 if (scan_result &&
63 enterprise_connectors::ContainsMalwareVerdict(scan_result->response)) {
64 return;
65 }
66
67 content::BrowserContext* browser_context =
68 content::DownloadItemUtils::GetBrowserContext(download);
69 Profile* profile = Profile::FromBrowserContext(browser_context);
70 if (profile) {
71 std::string raw_digest_sha256 = download->GetHash();
72 extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
73 ->OnDangerousDownloadEvent(
74 download->GetURL(), download->GetTargetFilePath().AsUTF8Unsafe(),
75 base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
76 DangerTypeToThreatType(download->GetDangerType()),
77 download->GetMimeType(), download->GetTotalBytes(),
78 EventResult::WARNED);
79 }
80 }
81
ReportDangerousDownloadWarningBypassed(download::DownloadItem * download,download::DownloadDangerType original_danger_type)82 void ReportDangerousDownloadWarningBypassed(
83 download::DownloadItem* download,
84 download::DownloadDangerType original_danger_type) {
85 content::BrowserContext* browser_context =
86 content::DownloadItemUtils::GetBrowserContext(download);
87 Profile* profile = Profile::FromBrowserContext(browser_context);
88 if (profile) {
89 std::string raw_digest_sha256 = download->GetHash();
90 extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
91 ->OnDangerousDownloadWarningBypassed(
92 download->GetURL(), download->GetTargetFilePath().AsUTF8Unsafe(),
93 base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
94 DangerTypeToThreatType(original_danger_type),
95 download->GetMimeType(), download->GetTotalBytes());
96 }
97 }
98
ReportAnalysisConnectorWarningBypassed(download::DownloadItem * download)99 void ReportAnalysisConnectorWarningBypassed(download::DownloadItem* download) {
100 content::BrowserContext* browser_context =
101 content::DownloadItemUtils::GetBrowserContext(download);
102 Profile* profile = Profile::FromBrowserContext(browser_context);
103 if (profile) {
104 std::string raw_digest_sha256 = download->GetHash();
105 enterprise_connectors::ScanResult* stored_result =
106 static_cast<enterprise_connectors::ScanResult*>(
107 download->GetUserData(enterprise_connectors::ScanResult::kKey));
108
109 ReportAnalysisConnectorWarningBypass(
110 profile, download->GetURL(),
111 download->GetTargetFilePath().AsUTF8Unsafe(),
112 base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
113 download->GetMimeType(),
114 extensions::SafeBrowsingPrivateEventRouter::kTriggerFileDownload,
115 DeepScanAccessPoint::DOWNLOAD, download->GetTotalBytes(),
116 stored_result ? stored_result->response
117 : enterprise_connectors::ContentAnalysisResponse());
118 }
119 }
120
121 } // namespace
122
DownloadReporter()123 DownloadReporter::DownloadReporter() {
124 // Profile manager can be null in unit tests.
125 if (g_browser_process->profile_manager())
126 g_browser_process->profile_manager()->AddObserver(this);
127 }
128
~DownloadReporter()129 DownloadReporter::~DownloadReporter() {
130 if (g_browser_process->profile_manager())
131 g_browser_process->profile_manager()->RemoveObserver(this);
132 }
133
OnProfileAdded(Profile * profile)134 void DownloadReporter::OnProfileAdded(Profile* profile) {
135 observed_profiles_.Add(profile);
136 observed_coordinators_.Add(SimpleDownloadManagerCoordinatorFactory::GetForKey(
137 profile->GetProfileKey()));
138 }
139
OnOffTheRecordProfileCreated(Profile * off_the_record)140 void DownloadReporter::OnOffTheRecordProfileCreated(Profile* off_the_record) {
141 OnProfileAdded(off_the_record);
142 }
143
OnProfileWillBeDestroyed(Profile * profile)144 void DownloadReporter::OnProfileWillBeDestroyed(Profile* profile) {
145 observed_profiles_.Remove(profile);
146 }
147
OnManagerGoingDown(download::SimpleDownloadManagerCoordinator * coordinator)148 void DownloadReporter::OnManagerGoingDown(
149 download::SimpleDownloadManagerCoordinator* coordinator) {
150 observed_coordinators_.Remove(coordinator);
151 }
152
OnDownloadCreated(download::DownloadItem * download)153 void DownloadReporter::OnDownloadCreated(download::DownloadItem* download) {
154 danger_types_[download] = download->GetDangerType();
155 observed_downloads_.Add(download);
156 }
157
OnDownloadDestroyed(download::DownloadItem * download)158 void DownloadReporter::OnDownloadDestroyed(download::DownloadItem* download) {
159 observed_downloads_.Remove(download);
160 danger_types_.erase(download);
161 }
162
OnDownloadUpdated(download::DownloadItem * download)163 void DownloadReporter::OnDownloadUpdated(download::DownloadItem* download) {
164 // If the update isn't a change in danger type, we can ignore it.
165 if (danger_types_[download] == download->GetDangerType())
166 return;
167
168 download::DownloadDangerType old_danger_type = danger_types_[download];
169 download::DownloadDangerType current_danger_type = download->GetDangerType();
170
171 if (!DangerTypeIsDangerous(old_danger_type) &&
172 DangerTypeIsDangerous(current_danger_type)) {
173 MaybeReportDangerousDownloadWarning(download);
174 }
175
176 if (DangerTypeIsDangerous(old_danger_type) &&
177 current_danger_type == download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED) {
178 ReportDangerousDownloadWarningBypassed(download, old_danger_type);
179 }
180
181 if (old_danger_type ==
182 download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING &&
183 current_danger_type == download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED) {
184 ReportAnalysisConnectorWarningBypassed(download);
185 }
186
187 danger_types_[download] = current_danger_type;
188 }
189
190 } // namespace safe_browsing
191