Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2385)

Unified Diff: chrome/browser/ssl/chrome_expect_ct_reporter.cc

Issue 2970913002: Implement CORS preflights for Expect-CT reports (Closed)
Patch Set: meacer nits Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ssl/chrome_expect_ct_reporter.cc
diff --git a/chrome/browser/ssl/chrome_expect_ct_reporter.cc b/chrome/browser/ssl/chrome_expect_ct_reporter.cc
index e56942601b05426dee75926286d1902f0f04351f..17c91a513e46bab71c3cb39d17da79ad5c204fe6 100644
--- a/chrome/browser/ssl/chrome_expect_ct_reporter.cc
+++ b/chrome/browser/ssl/chrome_expect_ct_reporter.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/ssl/chrome_expect_ct_reporter.h"
+#include <set>
#include <string>
#include "base/base64.h"
@@ -14,15 +15,39 @@
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/common/chrome_features.h"
+#include "net/base/load_flags.h"
#include "net/cert/ct_serialization.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/report_sender.h"
+#include "net/url_request/url_request_context.h"
namespace {
+// Returns true if |request| contains any of the |allowed_values| in a response
+// header field named |header|. |allowed_values| are expected to be lower-case
+// and the check is case-insensitive.
+bool HasHeaderValues(net::URLRequest* request,
+ const std::string& header,
+ const std::set<std::string>& allowed_values) {
+ std::string response_headers;
+ request->GetResponseHeaderByName(header, &response_headers);
+ const std::vector<std::string> response_values = base::SplitString(
+ response_headers, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ for (const auto& value : response_values) {
+ for (const auto& allowed : allowed_values) {
+ if (base::ToLowerASCII(allowed) == base::ToLowerASCII(value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
std::string TimeToISO8601(const base::Time& t) {
base::Time::Exploded exploded;
t.UTCExplode(&exploded);
@@ -129,7 +154,8 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
ChromeExpectCTReporter::ChromeExpectCTReporter(
net::URLRequestContext* request_context)
: report_sender_(
- new net::ReportSender(request_context, kTrafficAnnotation)) {}
+ new net::ReportSender(request_context, kTrafficAnnotation)),
+ request_context_(request_context) {}
ChromeExpectCTReporter::~ChromeExpectCTReporter() {}
@@ -173,7 +199,85 @@ void ChromeExpectCTReporter::OnExpectCTFailed(
UMA_HISTOGRAM_BOOLEAN("SSL.ExpectCTReportSendingAttempt", true);
- report_sender_->Send(report_uri, "application/json; charset=utf-8",
- serialized_report, base::Callback<void()>(),
+ SendPreflight(report_uri, serialized_report);
+}
+
+void ChromeExpectCTReporter::OnResponseStarted(net::URLRequest* request,
+ int net_error) {
+ auto preflight_it = inflight_preflights_.find(request);
+ DCHECK(inflight_preflights_.end() != inflight_preflights_.find(request));
+ PreflightInProgress* preflight = preflight_it->second.get();
+
+ const int response_code = request->GetResponseCode();
+
+ // Check that the preflight succeeded: it must have an HTTP OK status code,
+ // with the following headers:
+ // - Access-Control-Allow-Origin: * or null
+ // - Access-Control-Allow-Methods: POST
+ // - Access-Control-Allow-Headers: Content-Type
+
+ if (!request->status().is_success() || response_code < 200 ||
+ response_code > 299) {
+ RecordUMAOnFailure(preflight->report_uri, request->status().error(),
+ request->status().is_success() ? response_code : -1);
+ inflight_preflights_.erase(request);
+ // Do not use |preflight| after this point, since it has been erased above.
+ return;
+ }
+
+ if (!HasHeaderValues(request, "Access-Control-Allow-Origin", {"*", "null"}) ||
+ !HasHeaderValues(request, "Access-Control-Allow-Methods", {"post"}) ||
+ !HasHeaderValues(request, "Access-Control-Allow-Headers",
+ {"content-type"})) {
+ RecordUMAOnFailure(preflight->report_uri, request->status().error(),
+ response_code);
+ inflight_preflights_.erase(request);
+ // Do not use |preflight| after this point, since it has been erased above.
+ return;
+ }
+
+ report_sender_->Send(preflight->report_uri,
+ "application/expect-ct-report+json; charset=utf-8",
+ preflight->serialized_report, base::Callback<void()>(),
base::Bind(RecordUMAOnFailure));
+ inflight_preflights_.erase(request);
+}
+
+void ChromeExpectCTReporter::OnReadCompleted(net::URLRequest* request,
+ int bytes_read) {
+ NOTREACHED();
+}
+
+ChromeExpectCTReporter::PreflightInProgress::PreflightInProgress(
+ std::unique_ptr<net::URLRequest> request,
+ const std::string& serialized_report,
+ const GURL& report_uri)
+ : request(std::move(request)),
+ serialized_report(serialized_report),
+ report_uri(report_uri) {}
+
+ChromeExpectCTReporter::PreflightInProgress::~PreflightInProgress() {}
+
+void ChromeExpectCTReporter::SendPreflight(
+ const GURL& report_uri,
+ const std::string& serialized_report) {
+ std::unique_ptr<net::URLRequest> url_request =
+ request_context_->CreateRequest(report_uri, net::DEFAULT_PRIORITY, this,
+ kTrafficAnnotation);
+ url_request->SetLoadFlags(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA |
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ url_request->set_method("OPTIONS");
+
+ net::HttpRequestHeaders extra_headers;
+ extra_headers.SetHeader("Origin", "null");
+ extra_headers.SetHeader("Access-Control-Request-Method", "POST");
+ extra_headers.SetHeader("Access-Control-Request-Headers", "content-type");
+ url_request->SetExtraRequestHeaders(extra_headers);
+
+ net::URLRequest* raw_request = url_request.get();
+ inflight_preflights_[raw_request] = base::MakeUnique<PreflightInProgress>(
+ std::move(url_request), serialized_report, report_uri);
+ raw_request->Start();
}
« no previous file with comments | « chrome/browser/ssl/chrome_expect_ct_reporter.h ('k') | chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698