OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ping_manager.h" | 5 #include "chrome/browser/safe_browsing/ping_manager.h" |
6 | 6 |
7 #include <utility> | |
8 | |
9 #include "base/base64.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
12 #include "base/strings/string_util.h" | |
13 #include "base/strings/stringprintf.h" | |
14 #include "base/values.h" | |
15 #include "chrome/browser/safe_browsing/notification_image_reporter.h" | 8 #include "chrome/browser/safe_browsing/notification_image_reporter.h" |
16 #include "chrome/browser/safe_browsing/permission_reporter.h" | 9 #include "chrome/browser/safe_browsing/permission_reporter.h" |
17 #include "components/data_use_measurement/core/data_use_user_data.h" | |
18 #include "content/public/browser/browser_thread.h" | 10 #include "content/public/browser/browser_thread.h" |
19 #include "google_apis/google_api_keys.h" | |
20 #include "net/base/escape.h" | |
21 #include "net/base/load_flags.h" | |
22 #include "net/log/net_log_source_type.h" | |
23 #include "net/ssl/ssl_info.h" | |
24 #include "net/url_request/url_fetcher.h" | |
25 #include "net/url_request/url_request_context.h" | |
26 #include "net/url_request/url_request_context_getter.h" | 11 #include "net/url_request/url_request_context_getter.h" |
27 #include "net/url_request/url_request_status.h" | |
28 #include "third_party/skia/include/core/SkBitmap.h" | 12 #include "third_party/skia/include/core/SkBitmap.h" |
29 #include "url/gurl.h" | |
30 | 13 |
31 using content::BrowserThread; | 14 using content::BrowserThread; |
32 | 15 |
33 namespace { | |
34 // Returns a dictionary with "url"=|url-spec| and "data"=|payload| for | |
35 // netlogging the start phase of a ping. | |
36 std::unique_ptr<base::Value> NetLogPingStartCallback( | |
37 const net::NetLogWithSource& net_log, | |
38 const GURL& url, | |
39 const std::string& payload, | |
40 net::NetLogCaptureMode) { | |
41 std::unique_ptr<base::DictionaryValue> event_params( | |
42 new base::DictionaryValue()); | |
43 event_params->SetString("url", url.spec()); | |
44 event_params->SetString("payload", payload); | |
45 net_log.source().AddToEventParameters(event_params.get()); | |
46 return std::move(event_params); | |
47 } | |
48 | |
49 // Returns a dictionary with "url"=|url-spec|, "status"=|status| and | |
50 // "error"=|error| for netlogging the end phase of a ping. | |
51 std::unique_ptr<base::Value> NetLogPingEndCallback( | |
52 const net::NetLogWithSource& net_log, | |
53 const net::URLRequestStatus& status, | |
54 net::NetLogCaptureMode) { | |
55 std::unique_ptr<base::DictionaryValue> event_params( | |
56 new base::DictionaryValue()); | |
57 event_params->SetInteger("status", status.status()); | |
58 event_params->SetInteger("error", status.error()); | |
59 net_log.source().AddToEventParameters(event_params.get()); | |
60 return std::move(event_params); | |
61 } | |
62 | |
63 } // namespace | |
64 | |
65 namespace safe_browsing { | 16 namespace safe_browsing { |
66 | 17 |
67 // SafeBrowsingPingManager implementation ---------------------------------- | 18 // SafeBrowsingPingManager implementation ---------------------------------- |
68 | 19 |
69 // static | 20 // static |
70 std::unique_ptr<SafeBrowsingPingManager> SafeBrowsingPingManager::Create( | 21 std::unique_ptr<SafeBrowsingPingManager> SafeBrowsingPingManager::Create( |
71 net::URLRequestContextGetter* request_context_getter, | 22 net::URLRequestContextGetter* request_context_getter, |
72 const SafeBrowsingProtocolConfig& config) { | 23 const SafeBrowsingProtocolConfig& config) { |
73 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 24 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
74 return base::WrapUnique( | 25 return base::WrapUnique( |
75 new SafeBrowsingPingManager(request_context_getter, config)); | 26 new SafeBrowsingPingManager(request_context_getter, config)); |
76 } | 27 } |
77 | 28 |
78 SafeBrowsingPingManager::SafeBrowsingPingManager( | 29 SafeBrowsingPingManager::SafeBrowsingPingManager( |
79 net::URLRequestContextGetter* request_context_getter, | 30 net::URLRequestContextGetter* request_context_getter, |
80 const SafeBrowsingProtocolConfig& config) | 31 const SafeBrowsingProtocolConfig& config) |
81 : client_name_(config.client_name), | 32 : BasePingManager(request_context_getter, config) { |
82 request_context_getter_(request_context_getter), | |
83 url_prefix_(config.url_prefix) { | |
84 DCHECK(!url_prefix_.empty()); | |
85 | |
86 if (request_context_getter) { | 33 if (request_context_getter) { |
87 permission_reporter_ = base::MakeUnique<PermissionReporter>( | 34 permission_reporter_ = base::MakeUnique<PermissionReporter>( |
88 request_context_getter->GetURLRequestContext()); | 35 request_context_getter->GetURLRequestContext()); |
89 notification_image_reporter_ = base::MakeUnique<NotificationImageReporter>( | 36 notification_image_reporter_ = base::MakeUnique<NotificationImageReporter>( |
90 request_context_getter->GetURLRequestContext()); | 37 request_context_getter->GetURLRequestContext()); |
91 | |
92 net_log_ = net::NetLogWithSource::Make( | |
93 request_context_getter->GetURLRequestContext()->net_log(), | |
94 net::NetLogSourceType::SAFE_BROWSING); | |
95 } | 38 } |
96 | |
97 version_ = SafeBrowsingProtocolManagerHelper::Version(); | |
98 } | 39 } |
99 | 40 |
100 SafeBrowsingPingManager::~SafeBrowsingPingManager() { | 41 SafeBrowsingPingManager::~SafeBrowsingPingManager() { |
101 } | 42 } |
102 | 43 |
103 // net::URLFetcherDelegate implementation ---------------------------------- | |
104 | |
105 // All SafeBrowsing request responses are handled here. | |
106 void SafeBrowsingPingManager::OnURLFetchComplete( | |
107 const net::URLFetcher* source) { | |
108 net_log_.EndEvent( | |
109 net::NetLogEventType::SAFE_BROWSING_PING, | |
110 base::Bind(&NetLogPingEndCallback, net_log_, source->GetStatus())); | |
111 auto it = | |
112 std::find_if(safebrowsing_reports_.begin(), safebrowsing_reports_.end(), | |
113 [source](const std::unique_ptr<net::URLFetcher>& ptr) { | |
114 return ptr.get() == source; | |
115 }); | |
116 DCHECK(it != safebrowsing_reports_.end()); | |
117 safebrowsing_reports_.erase(it); | |
118 } | |
119 | |
120 // Sends a SafeBrowsing "hit" report. | |
121 void SafeBrowsingPingManager::ReportSafeBrowsingHit( | |
122 const safe_browsing::HitReport& hit_report) { | |
123 GURL report_url = SafeBrowsingHitUrl(hit_report); | |
124 std::unique_ptr<net::URLFetcher> report_ptr = net::URLFetcher::Create( | |
125 report_url, hit_report.post_data.empty() ? net::URLFetcher::GET | |
126 : net::URLFetcher::POST, | |
127 this); | |
128 net::URLFetcher* report = report_ptr.get(); | |
129 data_use_measurement::DataUseUserData::AttachToFetcher( | |
130 report, data_use_measurement::DataUseUserData::SAFE_BROWSING); | |
131 report_ptr->SetLoadFlags(net::LOAD_DISABLE_CACHE); | |
132 report_ptr->SetRequestContext(request_context_getter_.get()); | |
133 std::string post_data_base64; | |
134 if (!hit_report.post_data.empty()) { | |
135 report_ptr->SetUploadData("text/plain", hit_report.post_data); | |
136 base::Base64Encode(hit_report.post_data, &post_data_base64); | |
137 } | |
138 | |
139 net_log_.BeginEvent( | |
140 net::NetLogEventType::SAFE_BROWSING_PING, | |
141 base::Bind(&NetLogPingStartCallback, net_log_, | |
142 report_ptr->GetOriginalURL(), post_data_base64)); | |
143 | |
144 report->Start(); | |
145 safebrowsing_reports_.insert(std::move(report_ptr)); | |
146 } | |
147 | |
148 // Sends threat details for users who opt-in. | |
149 void SafeBrowsingPingManager::ReportThreatDetails(const std::string& report) { | |
150 GURL report_url = ThreatDetailsUrl(); | |
151 std::unique_ptr<net::URLFetcher> fetcher = | |
152 net::URLFetcher::Create(report_url, net::URLFetcher::POST, this); | |
153 data_use_measurement::DataUseUserData::AttachToFetcher( | |
154 fetcher.get(), data_use_measurement::DataUseUserData::SAFE_BROWSING); | |
155 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); | |
156 fetcher->SetRequestContext(request_context_getter_.get()); | |
157 fetcher->SetUploadData("application/octet-stream", report); | |
158 // Don't try too hard to send reports on failures. | |
159 fetcher->SetAutomaticallyRetryOn5xx(false); | |
160 | |
161 std::string report_base64; | |
162 base::Base64Encode(report, &report_base64); | |
163 net_log_.BeginEvent( | |
164 net::NetLogEventType::SAFE_BROWSING_PING, | |
165 base::Bind(&NetLogPingStartCallback, net_log_, fetcher->GetOriginalURL(), | |
166 report_base64)); | |
167 | |
168 fetcher->Start(); | |
169 safebrowsing_reports_.insert(std::move(fetcher)); | |
170 } | |
171 | |
172 void SafeBrowsingPingManager::ReportPermissionAction( | 44 void SafeBrowsingPingManager::ReportPermissionAction( |
173 const PermissionReportInfo& report_info) { | 45 const PermissionReportInfo& report_info) { |
174 permission_reporter_->SendReport(report_info); | 46 permission_reporter_->SendReport(report_info); |
175 } | 47 } |
176 | 48 |
177 void SafeBrowsingPingManager::ReportNotificationImage( | 49 void SafeBrowsingPingManager::ReportNotificationImage( |
178 Profile* profile, | 50 Profile* profile, |
179 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, | 51 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, |
180 const GURL& origin, | 52 const GURL& origin, |
181 const SkBitmap& image) { | 53 const SkBitmap& image) { |
182 notification_image_reporter_->ReportNotificationImageOnIO( | 54 notification_image_reporter_->ReportNotificationImageOnIO( |
183 profile, database_manager, origin, image); | 55 profile, database_manager, origin, image); |
184 } | 56 } |
185 | 57 |
186 GURL SafeBrowsingPingManager::SafeBrowsingHitUrl( | |
187 const safe_browsing::HitReport& hit_report) const { | |
188 DCHECK(hit_report.threat_type == SB_THREAT_TYPE_URL_MALWARE || | |
189 hit_report.threat_type == SB_THREAT_TYPE_URL_PHISHING || | |
190 hit_report.threat_type == SB_THREAT_TYPE_URL_UNWANTED || | |
191 hit_report.threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL || | |
192 hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL || | |
193 hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL); | |
194 std::string url = SafeBrowsingProtocolManagerHelper::ComposeUrl( | |
195 url_prefix_, "report", client_name_, version_, std::string(), | |
196 hit_report.extended_reporting_level); | |
197 | |
198 std::string threat_list = "none"; | |
199 switch (hit_report.threat_type) { | |
200 case SB_THREAT_TYPE_URL_MALWARE: | |
201 threat_list = "malblhit"; | |
202 break; | |
203 case SB_THREAT_TYPE_URL_PHISHING: | |
204 threat_list = "phishblhit"; | |
205 break; | |
206 case SB_THREAT_TYPE_URL_UNWANTED: | |
207 threat_list = "uwsblhit"; | |
208 break; | |
209 case SB_THREAT_TYPE_BINARY_MALWARE_URL: | |
210 threat_list = "binurlhit"; | |
211 break; | |
212 case SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL: | |
213 threat_list = "phishcsdhit"; | |
214 break; | |
215 case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL: | |
216 threat_list = "malcsdhit"; | |
217 break; | |
218 default: | |
219 NOTREACHED(); | |
220 } | |
221 | |
222 std::string threat_source = "none"; | |
223 switch (hit_report.threat_source) { | |
224 case safe_browsing::ThreatSource::DATA_SAVER: | |
225 threat_source = "ds"; | |
226 break; | |
227 case safe_browsing::ThreatSource::REMOTE: | |
228 threat_source = "rem"; | |
229 break; | |
230 case safe_browsing::ThreatSource::LOCAL_PVER3: | |
231 threat_source = "l3"; | |
232 break; | |
233 case safe_browsing::ThreatSource::LOCAL_PVER4: | |
234 threat_source = "l4"; | |
235 break; | |
236 case safe_browsing::ThreatSource::CLIENT_SIDE_DETECTION: | |
237 threat_source = "csd"; | |
238 break; | |
239 case safe_browsing::ThreatSource::UNKNOWN: | |
240 NOTREACHED(); | |
241 } | |
242 | |
243 // Add user_population component only if it's not empty. | |
244 std::string user_population_comp; | |
245 if (!hit_report.population_id.empty()) { | |
246 // Population_id should be URL-safe, but escape it and size-limit it | |
247 // anyway since it came from outside Chrome. | |
248 std::string up_str = | |
249 net::EscapeQueryParamValue(hit_report.population_id, true); | |
250 if (up_str.size() > 512) { | |
251 DCHECK(false) << "population_id is too long: " << up_str; | |
252 up_str = "UP_STRING_TOO_LONG"; | |
253 } | |
254 | |
255 user_population_comp = "&up=" + up_str; | |
256 } | |
257 | |
258 return GURL(base::StringPrintf( | |
259 "%s&evts=%s&evtd=%s&evtr=%s&evhr=%s&evtb=%d&src=%s&m=%d%s", url.c_str(), | |
260 threat_list.c_str(), | |
261 net::EscapeQueryParamValue(hit_report.malicious_url.spec(), true).c_str(), | |
262 net::EscapeQueryParamValue(hit_report.page_url.spec(), true).c_str(), | |
263 net::EscapeQueryParamValue(hit_report.referrer_url.spec(), true).c_str(), | |
264 hit_report.is_subresource, threat_source.c_str(), | |
265 hit_report.is_metrics_reporting_active, user_population_comp.c_str())); | |
266 } | |
267 | |
268 GURL SafeBrowsingPingManager::ThreatDetailsUrl() const { | |
269 std::string url = base::StringPrintf( | |
270 "%s/clientreport/malware?client=%s&appver=%s&pver=1.0", | |
271 url_prefix_.c_str(), | |
272 client_name_.c_str(), | |
273 version_.c_str()); | |
274 std::string api_key = google_apis::GetAPIKey(); | |
275 if (!api_key.empty()) { | |
276 base::StringAppendF(&url, "&key=%s", | |
277 net::EscapeQueryParamValue(api_key, true).c_str()); | |
278 } | |
279 return GURL(url); | |
280 } | |
281 | |
282 } // namespace safe_browsing | 58 } // namespace safe_browsing |
OLD | NEW |