| 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 |