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
3 // found in the LICENSE file.
5 #include "chrome/browser/safe_browsing/ping_manager.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/net/certificate_error_reporter.h"
12 #include "chrome/common/env_vars.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "google_apis/google_api_keys.h"
15 #include "net/base/escape.h"
16 #include "net/base/load_flags.h"
17 #include "net/ssl/ssl_info.h"
18 #include "net/url_request/certificate_report_sender.h"
19 #include "net/url_request/url_fetcher.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "net/url_request/url_request_status.h"
24 using chrome_browser_net::CertificateErrorReporter
;
25 using content::BrowserThread
;
28 // URLs to upload invalid certificate chain reports. The HTTP URL is
29 // preferred since a client seeing an invalid cert might not be able to
30 // make an HTTPS connection to report it.
31 const char kExtendedReportingUploadUrlInsecure
[] =
32 "http://safebrowsing.googleusercontent.com/safebrowsing/clientreport/"
34 const char kExtendedReportingUploadUrlSecure
[] =
35 "https://sb-ssl.google.com/safebrowsing/clientreport/chrome-certs";
38 // SafeBrowsingPingManager implementation ----------------------------------
41 SafeBrowsingPingManager
* SafeBrowsingPingManager::Create(
42 net::URLRequestContextGetter
* request_context_getter
,
43 const SafeBrowsingProtocolConfig
& config
) {
44 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
45 return new SafeBrowsingPingManager(request_context_getter
, config
);
48 SafeBrowsingPingManager::SafeBrowsingPingManager(
49 net::URLRequestContextGetter
* request_context_getter
,
50 const SafeBrowsingProtocolConfig
& config
)
51 : client_name_(config
.client_name
),
52 request_context_getter_(request_context_getter
),
53 url_prefix_(config
.url_prefix
) {
54 DCHECK(!url_prefix_
.empty());
56 if (request_context_getter
) {
57 // Set the upload URL and whether or not to send cookies with
58 // certificate reports sent to Safe Browsing servers.
59 bool use_insecure_certificate_upload_url
=
60 CertificateErrorReporter::IsHttpUploadUrlSupported();
62 net::CertificateReportSender::CookiesPreference cookies_preference
;
63 GURL certificate_upload_url
;
64 if (use_insecure_certificate_upload_url
) {
65 cookies_preference
= net::CertificateReportSender::DO_NOT_SEND_COOKIES
;
66 certificate_upload_url
= GURL(kExtendedReportingUploadUrlInsecure
);
68 cookies_preference
= net::CertificateReportSender::SEND_COOKIES
;
69 certificate_upload_url
= GURL(kExtendedReportingUploadUrlSecure
);
72 certificate_error_reporter_
.reset(new CertificateErrorReporter(
73 request_context_getter
->GetURLRequestContext(), certificate_upload_url
,
77 version_
= SafeBrowsingProtocolManagerHelper::Version();
80 SafeBrowsingPingManager::~SafeBrowsingPingManager() {
81 // Delete in-progress safebrowsing reports (hits and details).
82 STLDeleteContainerPointers(safebrowsing_reports_
.begin(),
83 safebrowsing_reports_
.end());
86 // net::URLFetcherDelegate implementation ----------------------------------
88 // All SafeBrowsing request responses are handled here.
89 void SafeBrowsingPingManager::OnURLFetchComplete(
90 const net::URLFetcher
* source
) {
91 Reports::iterator sit
= safebrowsing_reports_
.find(source
);
92 DCHECK(sit
!= safebrowsing_reports_
.end());
94 safebrowsing_reports_
.erase(sit
);
97 // Sends a SafeBrowsing "hit" for UMA users.
98 void SafeBrowsingPingManager::ReportSafeBrowsingHit(
99 const GURL
& malicious_url
,
100 const GURL
& page_url
,
101 const GURL
& referrer_url
,
103 SBThreatType threat_type
,
104 const std::string
& post_data
,
105 bool is_extended_reporting
) {
107 SafeBrowsingHitUrl(malicious_url
, page_url
, referrer_url
, is_subresource
,
108 threat_type
, is_extended_reporting
);
109 net::URLFetcher
* report
=
110 net::URLFetcher::Create(
112 post_data
.empty() ? net::URLFetcher::GET
: net::URLFetcher::POST
,
114 report
->SetLoadFlags(net::LOAD_DISABLE_CACHE
);
115 report
->SetRequestContext(request_context_getter_
.get());
116 if (!post_data
.empty())
117 report
->SetUploadData("text/plain", post_data
);
118 safebrowsing_reports_
.insert(report
);
122 // Sends malware details for users who opt-in.
123 void SafeBrowsingPingManager::ReportMalwareDetails(
124 const std::string
& report
) {
125 GURL report_url
= MalwareDetailsUrl();
126 net::URLFetcher
* fetcher
=
127 net::URLFetcher::Create(report_url
, net::URLFetcher::POST
, this)
129 fetcher
->SetLoadFlags(net::LOAD_DISABLE_CACHE
);
130 fetcher
->SetRequestContext(request_context_getter_
.get());
131 fetcher
->SetUploadData("application/octet-stream", report
);
132 // Don't try too hard to send reports on failures.
133 fetcher
->SetAutomaticallyRetryOn5xx(false);
135 safebrowsing_reports_
.insert(fetcher
);
138 void SafeBrowsingPingManager::ReportInvalidCertificateChain(
139 const std::string
& serialized_report
) {
140 DCHECK(certificate_error_reporter_
);
141 certificate_error_reporter_
->SendExtendedReportingReport(serialized_report
);
144 void SafeBrowsingPingManager::SetCertificateErrorReporterForTesting(
145 scoped_ptr
<CertificateErrorReporter
> certificate_error_reporter
) {
146 certificate_error_reporter_
= certificate_error_reporter
.Pass();
149 GURL
SafeBrowsingPingManager::SafeBrowsingHitUrl(
150 const GURL
& malicious_url
,
151 const GURL
& page_url
,
152 const GURL
& referrer_url
,
154 SBThreatType threat_type
,
155 bool is_extended_reporting
) const {
156 DCHECK(threat_type
== SB_THREAT_TYPE_URL_MALWARE
||
157 threat_type
== SB_THREAT_TYPE_URL_PHISHING
||
158 threat_type
== SB_THREAT_TYPE_URL_UNWANTED
||
159 threat_type
== SB_THREAT_TYPE_BINARY_MALWARE_URL
||
160 threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
||
161 threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL
);
162 std::string url
= SafeBrowsingProtocolManagerHelper::ComposeUrl(
163 url_prefix_
, "report", client_name_
, version_
, std::string(),
164 is_extended_reporting
);
165 std::string threat_list
= "none";
166 switch (threat_type
) {
167 case SB_THREAT_TYPE_URL_MALWARE
:
168 threat_list
= "malblhit";
170 case SB_THREAT_TYPE_URL_PHISHING
:
171 threat_list
= "phishblhit";
173 case SB_THREAT_TYPE_URL_UNWANTED
:
174 threat_list
= "uwsblhit";
176 case SB_THREAT_TYPE_BINARY_MALWARE_URL
:
177 threat_list
= "binurlhit";
179 case SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
:
180 threat_list
= "phishcsdhit";
182 case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL
:
183 threat_list
= "malcsdhit";
188 return GURL(base::StringPrintf("%s&evts=%s&evtd=%s&evtr=%s&evhr=%s&evtb=%d",
189 url
.c_str(), threat_list
.c_str(),
190 net::EscapeQueryParamValue(malicious_url
.spec(), true).c_str(),
191 net::EscapeQueryParamValue(page_url
.spec(), true).c_str(),
192 net::EscapeQueryParamValue(referrer_url
.spec(), true).c_str(),
196 GURL
SafeBrowsingPingManager::MalwareDetailsUrl() const {
197 std::string url
= base::StringPrintf(
198 "%s/clientreport/malware?client=%s&appver=%s&pver=1.0",
200 client_name_
.c_str(),
202 std::string api_key
= google_apis::GetAPIKey();
203 if (!api_key
.empty()) {
204 base::StringAppendF(&url
, "&key=%s",
205 net::EscapeQueryParamValue(api_key
, true).c_str());