Skip to content

Commit

Permalink
Upstream iOS implementation of safe browsing service.
Browse files Browse the repository at this point in the history
BUG=567727

Review URL: https://codereview.chromium.org/1528313002

Cr-Commit-Position: refs/heads/master@{#365538}
  • Loading branch information
sdefresne authored and Commit bot committed Dec 16, 2015
1 parent 5e3721a commit 5eaf7d2
Show file tree
Hide file tree
Showing 18 changed files with 2,520 additions and 1 deletion.
2 changes: 1 addition & 1 deletion components/components.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
'query_parser.gypi',
'rappor.gypi',
'renderer_context_menu.gypi',
'safe_browsing_db.gypi',
'search.gypi',
'search_engines.gypi',
'search_provider_logos.gypi',
Expand Down Expand Up @@ -124,7 +125,6 @@
'packed_ct_ev_whitelist.gypi',
'page_load_metrics.gypi',
'power.gypi',
'safe_browsing_db.gypi',
'safe_json.gypi',
'visitedlink.gypi',
'wallpaper.gypi',
Expand Down
2 changes: 2 additions & 0 deletions ios/chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ source_set("browser") {
"//components/bookmarks/managed",
"//components/browser_sync/browser",
"//components/browser_sync/common",
"//components/certificate_reporting",
"//components/component_updater",
"//components/content_settings/core/browser",
"//components/cookie_config",
Expand Down Expand Up @@ -519,6 +520,7 @@ source_set("browser") {
"//components/proxy_config",
"//components/rappor",
"//components/resources",
"//components/safe_browsing_db",
"//components/search",
"//components/search_engines",
"//components/security_interstitials/core",
Expand Down
2 changes: 2 additions & 0 deletions ios/chrome/browser/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ include_rules = [
"+components/bookmarks",
"+components/browser_sync/browser",
"+components/browser_sync/common",
"+components/certificate_reporting",
"+components/component_updater",
"+components/content_settings/core",
"+components/cookie_config",
Expand Down Expand Up @@ -46,6 +47,7 @@ include_rules = [
"+components/proxy_config",
"+components/rappor",
"+components/rlz",
"+components/safe_browsing_db",
"+components/search",
"+components/search_engines",
"+components/security_interstitials",
Expand Down
11 changes: 11 additions & 0 deletions ios/chrome/browser/safe_browsing/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//third_party/protobuf/proto_library.gni")

proto_library("proto") {
sources = [
"metadata.proto",
]
}
22 changes: 22 additions & 0 deletions ios/chrome/browser/safe_browsing/hit_report.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ios/chrome/browser/safe_browsing/hit_report.h"

#include "components/metrics/metrics_service.h"
#include "ios/chrome/browser/application_context.h"

namespace safe_browsing {

HitReport::HitReport() {}

HitReport::~HitReport() {}

bool IsMetricsReportingActive() {
const metrics::MetricsService* metrics =
GetApplicationContext()->GetMetricsService();
return metrics && metrics->reporting_active();
}

} // namespace safe_browsing
50 changes: 50 additions & 0 deletions ios/chrome/browser/safe_browsing/hit_report.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Datastructures that hold details of a Safe Browsing hit for reporting.

#ifndef IOS_CHROME_BROWSER_SAFE_BROWSING_HIT_REPORT_H_
#define IOS_CHROME_BROWSER_SAFE_BROWSING_HIT_REPORT_H_

#include "components/safe_browsing_db/util.h"
#include "url/gurl.h"

namespace safe_browsing {

// What service classified this threat as unsafe.
enum class ThreatSource {
UNKNOWN,
DATA_SAVER, // From the Data Reduction service.
LOCAL_PVER3, // From LocalSafeBrowingDatabaseManager, protocol v3
LOCAL_PVER4, // From LocalSafeBrowingDatabaseManager, protocol v4
REMOTE, // From RemoteSafeBrowingDatabaseManager
};

// Data to report about the contents of a particular threat (malware, phishing,
// unsafe download URL). If post_data is non-empty, the request will be
// sent as a POST instead of a GET.
struct HitReport {
HitReport();
~HitReport();

GURL malicious_url;
GURL page_url;
GURL referrer_url;

bool is_subresource;
SBThreatType threat_type;
ThreatSource threat_source;
bool is_extended_reporting;
bool is_metrics_reporting_active;

std::string post_data;
};

// Return true if the user has opted in to UMA metrics reporting.
// Used when filling out a HitReport.
bool IsMetricsReportingActive();

} // namespace safe_browsing

#endif // IOS_CHROME_BROWSER_SAFE_BROWSING_HIT_REPORT_H_
23 changes: 23 additions & 0 deletions ios/chrome/browser/safe_browsing/metadata.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

syntax = "proto2";

option optimize_for = LITE_RUNTIME;

package safe_browsing;

// Everything below this comment was copied from the page
// <https://developers.google.com/safe-browsing/developers_guide_v3>,
// section "Full Hash Metadata".

// Metadata for the goog-malware-shavar list.
message MalwarePatternType {
enum PATTERN_TYPE {
LANDING = 1;
DISTRIBUTION = 2;
}

required PATTERN_TYPE pattern_type = 1;
}
216 changes: 216 additions & 0 deletions ios/chrome/browser/safe_browsing/ping_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ios/chrome/browser/safe_browsing/ping_manager.h"

#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "components/certificate_reporting/error_reporter.h"
#include "google_apis/google_api_keys.h"
#include "ios/web/public/web_thread.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/ssl/ssl_info.h"
#include "net/url_request/certificate_report_sender.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"

namespace {
// URLs to upload invalid certificate chain reports. The HTTP URL is
// preferred since a client seeing an invalid cert might not be able to
// make an HTTPS connection to report it.
const char kExtendedReportingUploadUrlInsecure[] =
"http://safebrowsing.googleusercontent.com/safebrowsing/clientreport/"
"chrome-certs";
const char kExtendedReportingUploadUrlSecure[] =
"https://sb-ssl.google.com/safebrowsing/clientreport/chrome-certs";
} // namespace

namespace safe_browsing {

// SafeBrowsingPingManager implementation ----------------------------------

// static
SafeBrowsingPingManager* SafeBrowsingPingManager::Create(
net::URLRequestContextGetter* request_context_getter,
const SafeBrowsingProtocolConfig& config) {
DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO);
return new SafeBrowsingPingManager(request_context_getter, config);
}

SafeBrowsingPingManager::SafeBrowsingPingManager(
net::URLRequestContextGetter* request_context_getter,
const SafeBrowsingProtocolConfig& config)
: client_name_(config.client_name),
request_context_getter_(request_context_getter),
url_prefix_(config.url_prefix) {
DCHECK(!url_prefix_.empty());

if (request_context_getter) {
// Set the upload URL and whether or not to send cookies with
// certificate reports sent to Safe Browsing servers.
bool use_insecure_certificate_upload_url =
certificate_reporting::ErrorReporter::IsHttpUploadUrlSupported();

net::CertificateReportSender::CookiesPreference cookies_preference;
GURL certificate_upload_url;
if (use_insecure_certificate_upload_url) {
cookies_preference = net::CertificateReportSender::DO_NOT_SEND_COOKIES;
certificate_upload_url = GURL(kExtendedReportingUploadUrlInsecure);
} else {
cookies_preference = net::CertificateReportSender::SEND_COOKIES;
certificate_upload_url = GURL(kExtendedReportingUploadUrlSecure);
}

certificate_error_reporter_.reset(new certificate_reporting::ErrorReporter(
request_context_getter->GetURLRequestContext(), certificate_upload_url,
cookies_preference));
}

version_ = SafeBrowsingProtocolManagerHelper::Version();
}

SafeBrowsingPingManager::~SafeBrowsingPingManager() {
// Delete in-progress safebrowsing reports (hits and details).
STLDeleteContainerPointers(safebrowsing_reports_.begin(),
safebrowsing_reports_.end());
}

// net::URLFetcherDelegate implementation ----------------------------------

// All SafeBrowsing request responses are handled here.
void SafeBrowsingPingManager::OnURLFetchComplete(
const net::URLFetcher* source) {
Reports::iterator sit = safebrowsing_reports_.find(source);
DCHECK(sit != safebrowsing_reports_.end());
delete *sit;
safebrowsing_reports_.erase(sit);
}

// Sends a SafeBrowsing "hit" report.
void SafeBrowsingPingManager::ReportSafeBrowsingHit(
const safe_browsing::HitReport& hit_report) {
GURL report_url = SafeBrowsingHitUrl(hit_report);
net::URLFetcher* report =
net::URLFetcher::Create(report_url, hit_report.post_data.empty()
? net::URLFetcher::GET
: net::URLFetcher::POST,
this)
.release();
report->SetLoadFlags(net::LOAD_DISABLE_CACHE);
report->SetRequestContext(request_context_getter_.get());
if (!hit_report.post_data.empty())
report->SetUploadData("text/plain", hit_report.post_data);
safebrowsing_reports_.insert(report);
report->Start();
}

// Sends threat details for users who opt-in.
void SafeBrowsingPingManager::ReportThreatDetails(const std::string& report) {
GURL report_url = ThreatDetailsUrl();
net::URLFetcher* fetcher =
net::URLFetcher::Create(report_url, net::URLFetcher::POST, this)
.release();
fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
fetcher->SetRequestContext(request_context_getter_.get());
fetcher->SetUploadData("application/octet-stream", report);
// Don't try too hard to send reports on failures.
fetcher->SetAutomaticallyRetryOn5xx(false);
fetcher->Start();
safebrowsing_reports_.insert(fetcher);
}

void SafeBrowsingPingManager::ReportInvalidCertificateChain(
const std::string& serialized_report) {
DCHECK(certificate_error_reporter_);
certificate_error_reporter_->SendExtendedReportingReport(serialized_report);
}

void SafeBrowsingPingManager::SetCertificateErrorReporterForTesting(
scoped_ptr<certificate_reporting::ErrorReporter>
certificate_error_reporter) {
certificate_error_reporter_ = certificate_error_reporter.Pass();
}

GURL SafeBrowsingPingManager::SafeBrowsingHitUrl(
const safe_browsing::HitReport& hit_report) const {
DCHECK(hit_report.threat_type == SB_THREAT_TYPE_URL_MALWARE ||
hit_report.threat_type == SB_THREAT_TYPE_URL_PHISHING ||
hit_report.threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
hit_report.threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL ||
hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL ||
hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
std::string url = SafeBrowsingProtocolManagerHelper::ComposeUrl(
url_prefix_, "report", client_name_, version_, std::string(),
hit_report.is_extended_reporting);

std::string threat_list = "none";
switch (hit_report.threat_type) {
case SB_THREAT_TYPE_URL_MALWARE:
threat_list = "malblhit";
break;
case SB_THREAT_TYPE_URL_PHISHING:
threat_list = "phishblhit";
break;
case SB_THREAT_TYPE_URL_UNWANTED:
threat_list = "uwsblhit";
break;
case SB_THREAT_TYPE_BINARY_MALWARE_URL:
threat_list = "binurlhit";
break;
case SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL:
threat_list = "phishcsdhit";
break;
case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL:
threat_list = "malcsdhit";
break;
default:
NOTREACHED();
}

std::string threat_source = "none";
switch (hit_report.threat_source) {
case safe_browsing::ThreatSource::DATA_SAVER:
threat_source = "ds";
break;
case safe_browsing::ThreatSource::REMOTE:
threat_source = "rem";
break;
case safe_browsing::ThreatSource::LOCAL_PVER3:
threat_source = "l3";
break;
case safe_browsing::ThreatSource::LOCAL_PVER4:
threat_source = "l4";
break;
case safe_browsing::ThreatSource::UNKNOWN:
NOTREACHED();
}

return GURL(base::StringPrintf(
"%s&evts=%s&evtd=%s&evtr=%s&evhr=%s&evtb=%d&src=%s&m=%d", url.c_str(),
threat_list.c_str(),
net::EscapeQueryParamValue(hit_report.malicious_url.spec(), true).c_str(),
net::EscapeQueryParamValue(hit_report.page_url.spec(), true).c_str(),
net::EscapeQueryParamValue(hit_report.referrer_url.spec(), true).c_str(),
hit_report.is_subresource, threat_source.c_str(),
hit_report.is_metrics_reporting_active));
}

GURL SafeBrowsingPingManager::ThreatDetailsUrl() const {
std::string url = base::StringPrintf(
"%s/clientreport/malware?client=%s&appver=%s&pver=1.0",
url_prefix_.c_str(), client_name_.c_str(), version_.c_str());
std::string api_key = google_apis::GetAPIKey();
if (!api_key.empty()) {
base::StringAppendF(&url, "&key=%s",
net::EscapeQueryParamValue(api_key, true).c_str());
}
return GURL(url);
}

} // namespace safe_browsing
Loading

0 comments on commit 5eaf7d2

Please sign in to comment.