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/protocol_manager.h" | 5 #include "chrome/browser/safe_browsing/protocol_manager.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/environment.h" | 8 #include "base/environment.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 const std::string get_hash = FormatGetHash(prefixes); | 231 const std::string get_hash = FormatGetHash(prefixes); |
232 | 232 |
233 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); | 233 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
234 fetcher->SetRequestContext(request_context_getter_.get()); | 234 fetcher->SetRequestContext(request_context_getter_.get()); |
235 fetcher->SetUploadData("text/plain", get_hash); | 235 fetcher->SetUploadData("text/plain", get_hash); |
236 fetcher->Start(); | 236 fetcher->Start(); |
237 } | 237 } |
238 | 238 |
239 std::string SafeBrowsingProtocolManager::GetV4HashRequest( | 239 std::string SafeBrowsingProtocolManager::GetV4HashRequest( |
240 const std::vector<SBPrefix>& prefixes, | 240 const std::vector<SBPrefix>& prefixes, |
241 const std::vector<PlatformType>& platforms, | |
241 ThreatType threat_type) { | 242 ThreatType threat_type) { |
242 // Build the request. Client info and client states are not added to the | 243 // Build the request. Client info and client states are not added to the |
243 // request protocol buffer. Client info is passed as params in the url. | 244 // request protocol buffer. Client info is passed as params in the url. |
244 FindFullHashesRequest req; | 245 FindFullHashesRequest req; |
245 ThreatInfo* info = req.mutable_threat_info(); | 246 ThreatInfo* info = req.mutable_threat_info(); |
246 info->add_threat_types(threat_type); | 247 info->add_threat_types(threat_type); |
247 info->add_platform_types(CHROME_PLATFORM); | |
248 info->add_threat_entry_types(URL_EXPRESSION); | 248 info->add_threat_entry_types(URL_EXPRESSION); |
249 for (const PlatformType p : platforms) { | |
250 info->add_platform_types(p); | |
251 } | |
249 for (const SBPrefix& prefix : prefixes) { | 252 for (const SBPrefix& prefix : prefixes) { |
250 std::string hash; | 253 std::string hash; |
251 hash.append(reinterpret_cast<const char*>(&prefix), sizeof(SBPrefix)); | 254 hash.append(reinterpret_cast<const char*>(&prefix), sizeof(SBPrefix)); |
252 info->add_threat_entries()->set_hash(hash); | 255 info->add_threat_entries()->set_hash(hash); |
253 } | 256 } |
254 | 257 |
255 // Serialize and Base64 encode. | 258 // Serialize and Base64 encode. |
256 std::string req_data, req_base64; | 259 std::string req_data, req_base64; |
257 req.SerializeToString(&req_data); | 260 req.SerializeToString(&req_data); |
258 base::Base64Encode(req_data, &req_base64); | 261 base::Base64Encode(req_data, &req_base64); |
259 | 262 |
260 return req_base64; | 263 return req_base64; |
261 } | 264 } |
262 | 265 |
266 bool SafeBrowsingProtocolManager::ParseV4HashResponse( | |
267 const std::string& data, | |
268 std::vector<SBFullHashResult>* full_hashes, | |
269 base::TimeDelta* negative_cache_duration) { | |
270 FindFullHashesResponse response; | |
271 | |
272 if (!response.ParseFromString(data)) | |
273 return false; | |
274 | |
275 if (response.has_negative_cache_duration()) { | |
276 // Seconds resolution is good enough so we ignore the nanos field. | |
277 *negative_cache_duration = base::TimeDelta::FromSeconds( | |
278 response.negative_cache_duration().seconds()); | |
279 } | |
280 | |
281 // Loop over the threat matches and fill in full_hashes. | |
282 for (const ThreatMatch& match : response.matches()) { | |
283 // Make sure the platform and threat entry type match. | |
284 if (!(match.has_threat_entry_type() && | |
285 match.threat_entry_type() == URL_EXPRESSION && | |
286 match.has_threat())) { | |
287 continue; | |
288 } | |
289 | |
290 // Fill in the full hash. | |
291 SBFullHashResult result; | |
292 result.hash = StringToSBFullHash(match.threat().hash()); | |
awoz
2016/01/05 17:20:10
Should the threat type also be passed back?
awoz
2016/01/12 22:55:04
This is irrelevant since only one threat type is b
| |
293 | |
294 if (match.has_cache_duration()) { | |
295 // Seconds resolution is good enough so we ignore the nanos field. | |
296 result.cache_duration = base::TimeDelta::FromSeconds( | |
297 match.cache_duration().seconds()); | |
298 } | |
299 | |
300 // Different threat types will handle the metadata differently. | |
301 if (match.has_threat_type() && match.threat_type() == API_ABUSE && | |
302 match.has_platform_type() && | |
303 match.platform_type() == CHROME_PLATFORM && | |
304 match.has_threat_entry_metadata()) { | |
305 // For API Abuse, store a csv of the returned permissions. | |
306 for (const ThreatEntryMetadata::MetadataEntry& m : | |
307 match.threat_entry_metadata().entries()) { | |
308 if (m.key() == "permission") { | |
309 result.metadata += m.value() + ","; | |
310 } | |
311 } | |
312 } | |
313 | |
314 full_hashes->push_back(result); | |
315 } | |
316 return true; | |
317 } | |
318 | |
263 void SafeBrowsingProtocolManager::GetV4FullHashes( | 319 void SafeBrowsingProtocolManager::GetV4FullHashes( |
264 const std::vector<SBPrefix>& prefixes, | 320 const std::vector<SBPrefix>& prefixes, |
321 const std::vector<PlatformType>& platforms, | |
265 ThreatType threat_type, | 322 ThreatType threat_type, |
266 FullHashCallback callback) { | 323 FullHashCallback callback) { |
267 DCHECK(CalledOnValidThread()); | 324 DCHECK(CalledOnValidThread()); |
268 // TODO(kcarattini): Implement backoff behavior. | 325 // TODO(kcarattini): Implement backoff behavior. |
269 | 326 |
270 std::string req_base64 = GetV4HashRequest(prefixes, threat_type); | 327 std::string req_base64 = GetV4HashRequest(prefixes, platforms, threat_type); |
271 GURL gethash_url = GetV4HashUrl(req_base64); | 328 GURL gethash_url = GetV4HashUrl(req_base64); |
272 | 329 |
273 net::URLFetcher* fetcher = | 330 net::URLFetcher* fetcher = |
274 net::URLFetcher::Create(url_fetcher_id_++, gethash_url, | 331 net::URLFetcher::Create(url_fetcher_id_++, gethash_url, |
275 net::URLFetcher::GET, this) | 332 net::URLFetcher::GET, this) |
276 .release(); | 333 .release(); |
277 // TODO(kcarattini): Implement a new response processor. | |
278 v4_hash_requests_[fetcher] = FullHashDetails(callback, | 334 v4_hash_requests_[fetcher] = FullHashDetails(callback, |
279 false /* is_download */); | 335 false /* is_download */); |
280 | 336 |
281 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); | 337 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
282 fetcher->SetRequestContext(request_context_getter_.get()); | 338 fetcher->SetRequestContext(request_context_getter_.get()); |
283 fetcher->Start(); | 339 fetcher->Start(); |
284 } | 340 } |
285 | 341 |
286 void SafeBrowsingProtocolManager::GetFullHashesWithApis( | 342 void SafeBrowsingProtocolManager::GetFullHashesWithApis( |
287 const std::vector<SBPrefix>& prefixes, | 343 const std::vector<SBPrefix>& prefixes, |
288 FullHashCallback callback) { | 344 FullHashCallback callback) { |
289 GetV4FullHashes(prefixes, API_ABUSE, callback); | 345 std::vector<PlatformType> platform; |
346 platform.push_back(CHROME_PLATFORM); | |
347 GetV4FullHashes(prefixes, platform, API_ABUSE, callback); | |
290 } | 348 } |
291 | 349 |
292 void SafeBrowsingProtocolManager::GetNextUpdate() { | 350 void SafeBrowsingProtocolManager::GetNextUpdate() { |
293 DCHECK(CalledOnValidThread()); | 351 DCHECK(CalledOnValidThread()); |
294 if (request_.get() || request_type_ != NO_REQUEST) | 352 if (request_.get() || request_type_ != NO_REQUEST) |
295 return; | 353 return; |
296 | 354 |
297 IssueUpdateRequest(); | 355 IssueUpdateRequest(); |
298 } | 356 } |
299 | 357 |
300 // net::URLFetcherDelegate implementation ---------------------------------- | 358 // net::URLFetcherDelegate implementation ---------------------------------- |
301 | 359 |
302 // All SafeBrowsing request responses are handled here. | 360 // All SafeBrowsing request responses are handled here. |
303 // TODO(paulg): Clarify with the SafeBrowsing team whether a failed parse of a | 361 // TODO(paulg): Clarify with the SafeBrowsing team whether a failed parse of a |
304 // chunk should retry the download and parse of that chunk (and | 362 // chunk should retry the download and parse of that chunk (and |
305 // what back off / how many times to try), and if that effects the | 363 // what back off / how many times to try), and if that effects the |
306 // update back off. For now, a failed parse of the chunk means we | 364 // update back off. For now, a failed parse of the chunk means we |
307 // drop it. This isn't so bad because the next UPDATE_REQUEST we | 365 // drop it. This isn't so bad because the next UPDATE_REQUEST we |
308 // do will report all the chunks we have. If that chunk is still | 366 // do will report all the chunks we have. If that chunk is still |
309 // required, the SafeBrowsing servers will tell us to get it again. | 367 // required, the SafeBrowsing servers will tell us to get it again. |
310 void SafeBrowsingProtocolManager::OnURLFetchComplete( | 368 void SafeBrowsingProtocolManager::OnURLFetchComplete( |
311 const net::URLFetcher* source) { | 369 const net::URLFetcher* source) { |
312 DCHECK(CalledOnValidThread()); | 370 DCHECK(CalledOnValidThread()); |
313 scoped_ptr<const net::URLFetcher> fetcher; | 371 scoped_ptr<const net::URLFetcher> fetcher; |
314 | 372 |
315 HashRequests::iterator it = hash_requests_.find(source); | 373 HashRequests::iterator it = hash_requests_.find(source); |
374 HashRequests::iterator v4_it = v4_hash_requests_.find(source); | |
316 int response_code = source->GetResponseCode(); | 375 int response_code = source->GetResponseCode(); |
317 net::URLRequestStatus status = source->GetStatus(); | 376 net::URLRequestStatus status = source->GetStatus(); |
318 RecordHttpResponseOrErrorCode(kUmaHashResponseMetricName, status, | 377 RecordHttpResponseOrErrorCode(kUmaHashResponseMetricName, status, |
319 response_code); | 378 response_code); |
320 if (it != hash_requests_.end()) { | 379 if (it != hash_requests_.end()) { |
321 // GetHash response. | 380 // GetHash response. |
322 fetcher.reset(it->first); | 381 fetcher.reset(it->first); |
323 const FullHashDetails& details = it->second; | 382 const FullHashDetails& details = it->second; |
324 std::vector<SBFullHashResult> full_hashes; | 383 std::vector<SBFullHashResult> full_hashes; |
325 base::TimeDelta cache_lifetime; | 384 base::TimeDelta cache_lifetime; |
(...skipping 29 matching lines...) Expand all Loading... | |
355 << " failed with error: " << response_code; | 414 << " failed with error: " << response_code; |
356 } | 415 } |
357 } | 416 } |
358 | 417 |
359 // Invoke the callback with full_hashes, even if there was a parse error or | 418 // Invoke the callback with full_hashes, even if there was a parse error or |
360 // an error response code (in which case full_hashes will be empty). The | 419 // an error response code (in which case full_hashes will be empty). The |
361 // caller can't be blocked indefinitely. | 420 // caller can't be blocked indefinitely. |
362 details.callback.Run(full_hashes, cache_lifetime); | 421 details.callback.Run(full_hashes, cache_lifetime); |
363 | 422 |
364 hash_requests_.erase(it); | 423 hash_requests_.erase(it); |
424 } else if (v4_it != v4_hash_requests_.end()) { | |
425 // V4 FindFullHashes response. | |
426 fetcher.reset(v4_it->first); | |
427 const FullHashDetails& details = v4_it->second; | |
428 std::vector<SBFullHashResult> full_hashes; | |
429 base::TimeDelta negative_cache_duration; | |
430 if (status.is_success() && response_code == net::HTTP_OK) { | |
431 // TODO(kcarattini): Add UMA reporting. | |
432 // TODO(kcarattini): Implement backoff and minimum waiting duration | |
433 // compliance. | |
434 std::string data; | |
435 source->GetResponseAsString(&data); | |
436 if (!ParseV4HashResponse(data, &full_hashes, &negative_cache_duration)) { | |
437 full_hashes.clear(); | |
438 // TODO(kcarattini): Add UMA reporting. | |
439 } | |
440 } else { | |
441 // TODO(kcarattini): Handle error by setting backoff interval. | |
442 // TODO(kcarattini): Add UMA reporting. | |
443 if (status.status() == net::URLRequestStatus::FAILED) { | |
444 DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << | |
445 source->GetURL() << " failed with error: " << status.error(); | |
446 } else { | |
447 DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << | |
448 source->GetURL() << " failed with error: " << response_code; | |
449 } | |
450 } | |
451 | |
452 // Invoke the callback with full_hashes, even if there was a parse error or | |
453 // an error response code (in which case full_hashes will be empty). The | |
454 // caller can't be blocked indefinitely. | |
455 details.callback.Run(full_hashes, negative_cache_duration); | |
456 | |
457 v4_hash_requests_.erase(it); | |
365 } else { | 458 } else { |
366 // Update or chunk response. | 459 // Update or chunk response. |
367 fetcher.reset(request_.release()); | 460 fetcher.reset(request_.release()); |
368 | 461 |
369 if (request_type_ == UPDATE_REQUEST || | 462 if (request_type_ == UPDATE_REQUEST || |
370 request_type_ == BACKUP_UPDATE_REQUEST) { | 463 request_type_ == BACKUP_UPDATE_REQUEST) { |
371 if (!fetcher.get()) { | 464 if (!fetcher.get()) { |
372 // We've timed out waiting for an update response, so we've cancelled | 465 // We've timed out waiting for an update response, so we've cancelled |
373 // the update request and scheduled a new one. Ignore this response. | 466 // the update request and scheduled a new one. Ignore this response. |
374 return; | 467 return; |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
861 SafeBrowsingProtocolManager::FullHashDetails::FullHashDetails( | 954 SafeBrowsingProtocolManager::FullHashDetails::FullHashDetails( |
862 FullHashCallback callback, | 955 FullHashCallback callback, |
863 bool is_download) | 956 bool is_download) |
864 : callback(callback), is_download(is_download) {} | 957 : callback(callback), is_download(is_download) {} |
865 | 958 |
866 SafeBrowsingProtocolManager::FullHashDetails::~FullHashDetails() {} | 959 SafeBrowsingProtocolManager::FullHashDetails::~FullHashDetails() {} |
867 | 960 |
868 SafeBrowsingProtocolManagerDelegate::~SafeBrowsingProtocolManagerDelegate() {} | 961 SafeBrowsingProtocolManagerDelegate::~SafeBrowsingProtocolManagerDelegate() {} |
869 | 962 |
870 } // namespace safe_browsing | 963 } // namespace safe_browsing |
OLD | NEW |