Commit f71582a1 authored by xingx@chromium.org's avatar xingx@chromium.org

Implement client side tamper detection logic.

The Chrome data reduction feature relies on HTTP headers to 
work correctly and efficiently with the data reduction 
proxy. This include both standard HTTP headers (like Via) 
and custom headers (like Chrome-Proxy). Tampering on these 
headers could lead to miserable user experience, taking 10s 
to load some pages, for example.

In the past, we have seen such headers being stripped by 
middle box proxies (for example, the WWW-Authenticate header 
was stripped by some carrier). It has been known that mobile 
carriers are doing HTTP traffic optimizations. We also want 
to know whether mobile carriers are trying to "optimize" the 
already optimized data reduction proxy response body, which 
might lead to higher cost to users.


We propose a mechanism in Chromium to enable us to learn the 
scale and the types of such tampers. In short, the mechanism 
will check whether a predefined set of HTTP response headers 
and the response body have been changed in a way that could 
affect the data reduction proxy. It will detect such changes 
by using pre-calculated header (and probably content) hashes 
sent by the server. Chromium will report through UMA the 
count of each tamper types has happened. This will only be 
enabled for a fraction of the data reduction proxy users.

BUG=381907

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

Cr-Commit-Position: refs/heads/master@{#288492}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288492 0039d316-1c4b-4281-b951-d872f2087c98
parent 3571512c
......@@ -82,6 +82,7 @@
'data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_settings_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_tamper_detection_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_usage_stats_unittest.cc',
'data_reduction_proxy/common/data_reduction_proxy_headers_unittest.cc',
'dom_distiller/core/article_entry_unittest.cc',
......
......@@ -36,6 +36,8 @@
'data_reduction_proxy/browser/data_reduction_proxy_protocol.h',
'data_reduction_proxy/browser/data_reduction_proxy_settings.cc',
'data_reduction_proxy/browser/data_reduction_proxy_settings.h',
'data_reduction_proxy/browser/data_reduction_proxy_tamper_detection.cc',
'data_reduction_proxy/browser/data_reduction_proxy_tamper_detection.h',
'data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc',
'data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h',
],
......
......@@ -7,6 +7,7 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
......@@ -58,6 +59,10 @@ bool MaybeBypassProxyAndPrepareToRetry(
if (data_reduction_proxies.first.is_empty())
return false;
DataReductionProxyTamperDetection::DetectAndReport(
original_response_headers,
data_reduction_proxies.first.SchemeIsSecure());
DataReductionProxyInfo data_reduction_proxy_info;
net::ProxyService::DataReductionProxyBypassType bypass_type =
GetDataReductionProxyBypassType(original_response_headers,
......
// Copyright 2014 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.
// This file implements the tamper detection logic, which detects whether
// there are middleboxes and whether they are tampering with the response
// which may break correct communication and data transfer between the Chromium
// client and the data reduction proxy.
//
// At a high level, the tamper detection process works in two steps:
// 1. The data reduction proxy selects a fraction of responses to analyze,
// generates a series of fingerprints for each, and appends them to the
// Chrome-Proxy response headers;
// 2. The client re-generate the fingerprints using the same method as the
// proxy, compares them to the fingerprints in the response, and generates
// UMA. A response is considered to have been tampered with if the
// fingerprints do not match.
//
// Four fingerprints are generated by the data reduction proxy:
// 1. Fingerprint of the Chrome-Proxy header, which is designed to check
// whether the Chrome-Proxy header has been modified or not;
// 2. Fingerprint of the Via header, which is designed to check whether there
// are middleboxes between the Chromium client and the data reduction proxy;
// 3. Fingerprint of a list of headers, which is designed to check whether the
// values of a list of headers (list is defined by the data reduction proxy)
// have been modified or deleted;
// 4. Fingerprint of the Content-Length header, which is designed to check
// whether the response body has been modified or not (the code assumes that
// different Content-Length values indicate different response bodies).
//
// On the client side, the fingerprint of the Chrome-Proxy header will be
// checked first. If the fingerprint indicates that the Chrome-Proxy header has
// not been modified, then the other fingerprints will be considered to be
// reliable and will be checked next; if not, then it's possible that the other
// fingerprints have been tampered with and thus they will not be checked.
// If middlebox removes all the fingerprints then such tampering will not be
// detected.
//
// Detected tampering information will be reported to UMA. In general, for each
// fingerprint, the client reports the number of responses that have been
// tampered with for different carriers. For the fingerprint of the
// Content-Length header, which indicates whether the response body has been
// modified or not, the reports of tampering are separated by MIME type of the
// response body.
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_TAMPER_DETECTION_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_TAMPER_DETECTION_H_
#include <map>
#include <string>
#include <vector>
#include "net/proxy/proxy_service.h"
namespace net {
class HttpResponseHeaders;
}
namespace data_reduction_proxy {
// Detects if the response sent by the data reduction proxy has been modified
// by intermediaries on the Web.
class DataReductionProxyTamperDetection {
public:
// Checks if the response contains tamper detection fingerprints added by the
// data reduction proxy, and determines if the response had been tampered
// with if so. Results are reported to UMA. HTTP and HTTPS traffic are
// reported separately, specified by |scheme_is_https|. Returns true if
// the response has been tampered with.
static bool DetectAndReport(const net::HttpResponseHeaders* headers,
bool scheme_is_https);
// Tamper detection checks |response_headers|. Histogram events are reported
// by |carrier_id|; |scheme_is_https| determines which histogram to report
// (HTTP and HTTPS are reported separately).
DataReductionProxyTamperDetection(
const net::HttpResponseHeaders* response_headers,
bool scheme_is_https,
unsigned carrier_id);
virtual ~DataReductionProxyTamperDetection();
private:
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
TestFingerprintCommon);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
ChromeProxy);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
Via);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
OtherHeaders);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
ContentLength);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
HeaderRemoving);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
ValuesToSortedString);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
GetHeaderValues);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
DetectAndReport);
// Returns the result of validating Chrome-Proxy header.
bool ValidateChromeProxyHeader(const std::string& fingerprint) const;
// Reports UMA for tampering of the Chrome-Proxy header.
void ReportUMAforChromeProxyHeaderValidation() const;
// Returns the result of validating the Via header. |has_chrome_proxy|
// indicates that the data reduction proxy's Via header occurs or not.
bool ValidateViaHeader(const std::string& fingerprint,
bool* has_chrome_proxy_via_header) const;
// Reports UMA for tampering of the Via header.
void ReportUMAforViaHeaderValidation(bool has_chrome_proxy_via_header) const;
// Returns the result of validating a list of headers.
bool ValidateOtherHeaders(const std::string& fingerprint) const;
// Reports UMA for tampering of values of the list of headers.
void ReportUMAforOtherHeadersValidation() const;
// Returns the result of validating the Content-Length header.
bool ValidateContentLengthHeader(const std::string& fingerprint) const;
// Reports UMA for tampering of the Content-Length header.
void ReportUMAforContentLengthHeaderValidation() const;
// Returns a string representation of |values|.
static std::string ValuesToSortedString(std::vector<std::string>* values);
// Returns raw MD5 hash value for a given string |input|. It is different to
// base::MD5String which is base16 encoded.
static void GetMD5(const std::string& input, std::string* output);
// Returns all the values of |header_name| of the response |headers| as a
// vector. This function is used for values that need to be sorted later.
static std::vector<std::string> GetHeaderValues(
const net::HttpResponseHeaders* headers,
const std::string& header_name);
// Pointer to response headers.
const net::HttpResponseHeaders* response_headers_;
// If true, the connection to the data reduction proxy is over HTTPS;
const bool scheme_is_https_;
// Carrier ID: the numeric name of the current registered operator.
const unsigned carrier_id_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyTamperDetection);
};
} // namespace data_reduction_proxy
#endif // COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_TAMPER_DETECTION_H_
......@@ -3426,6 +3426,78 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
<histogram name="DataReductionProxy.HeaderTamperDetectionHTTP">
<owner>xingx@chromium.org</owner>
<owner>bolian@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
For each carrier, the total number of HTTP responses that have been checked
for tampering. This assumes the data reduction proxy injected fingerprints
have not been tampered with. Only the data reduction proxy responses with
200 OK response code are checked.
</summary>
</histogram>
<histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS">
<owner>xingx@chromium.org</owner>
<owner>bolian@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
For each carrier, the total number of HTTPS responses that have been checked
for tampering. This assumes the data reduction proxy injected fingerprints
have not been tampered with. Only the data reduction proxy responses with
200 OK response code are checked.
</summary>
</histogram>
<histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTP">
<owner>xingx@chromium.org</owner>
<owner>bolian@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
For each carrier, the total number of HTTP responses that passed the tamper
detection. This assumes the data reduction proxy injected fingerprints have
not been tampered with. Only the data reduction proxy responses with 200 OK
response code are checked.
</summary>
</histogram>
<histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTPS">
<owner>xingx@chromium.org</owner>
<owner>bolian@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
For each carrier, the total number of HTTPs responses that passed the tamper
detection. This assumes the data reduction proxy injected fingerprints have
not been tampered with. Only the data reduction proxy responses with 200 OK
response code are checked.
</summary>
</histogram>
<histogram name="DataReductionProxy.HeaderTamperedHTTP">
<owner>xingx@chromium.org</owner>
<owner>bolian@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
The total number of HTTP responses that some part (specified by suffix name)
have been tampered with. This assumes the data reduction proxy injected
fingerprints have not been tampered with. Only the data reduction proxy
responses with 200 OK response code are checked.
</summary>
</histogram>
<histogram name="DataReductionProxy.HeaderTamperedHTTPS">
<owner>xingx@chromium.org</owner>
<owner>bolian@chromium.org</owner>
<owner>bengr@chromium.org</owner>
<summary>
The total number of HTTPS responses that some part (specified by suffix
name) have been tampered with. This assumes the data reduction proxy
injected fingerprints have not been tampered with. Only the data reduction
proxy responses with 200 OK response code are checked.
</summary>
</histogram>
<histogram name="DataReductionProxy.NetworkChangeEvents"
enum="DataReductionProxyNetworkChangeEvent">
<owner>bengr@chromium.org</owner>
......@@ -50208,6 +50280,78 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<affected-histogram name="PLT.PT_StartToFinish"/>
</histogram_suffixes>
<histogram_suffixes name="DataReductionProxy_TamperingFingerprints"
separator="_">
<suffix name="ChromeProxy"
label="for each carrier, number of tamperings detected on Chrome-Proxy
header"/>
<suffix name="ContentLength"
label="for each carrier, total number of responses whose Content-Length
header has been tampered with"/>
<suffix name="ContentLength_CSS"
label="for each carrier, number of CSS responses whose Content-Length
header has been tampered with"/>
<suffix name="ContentLength_Image"
label="for each carrier, number of image responses whose Content-Length
header has been tampered with"/>
<suffix name="ContentLength_JS"
label="for each carrier, number of JavaScript responses whose
Content-Length header has been tampered with"/>
<suffix name="ContentLength_Other"
label="for each carrier, number of other type responses whose
Content-Length header has been tampered with"/>
<suffix name="OtherHeaders"
label="for each carrier, number of tamperings detected on a list of
headers"/>
<suffix name="Via"
label="for each carrier, number of tamperings detected on Via header"/>
<suffix name="Via_Missing"
label="for each carrier, number of responses whose data reduction
proxy's Via header is missing"/>
<affected-histogram name="DataReductionProxy.HeaderTamperedHTTP"/>
<affected-histogram name="DataReductionProxy.HeaderTamperedHTTPS"/>
</histogram_suffixes>
<histogram_suffixes name="DataReductionProxy_TamperingTotal" separator="_">
<suffix name="Total" label="total number of tamperings detected"/>
<affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTP"/>
<affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS"/>
<affected-histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTP"/>
<affected-histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTPS"/>
<affected-histogram name="DataReductionProxy.HeaderTamperedHTTP_ChromeProxy"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTP_ContentLength"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTP_ContentLength_CSS"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTP_ContentLength_Image"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTP_ContentLength_JS"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTP_ContentLength_Other"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTP_OtherHeaders"/>
<affected-histogram name="DataReductionProxy.HeaderTamperedHTTP_Via"/>
<affected-histogram name="DataReductionProxy.HeaderTamperedHTTP_Via_Missing"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_ChromeProxy"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_ContentLength"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_ContentLength_CSS"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_ContentLength_Image"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_ContentLength_JS"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_ContentLength_Other"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_OtherHeaders"/>
<affected-histogram name="DataReductionProxy.HeaderTamperedHTTPS_Via"/>
<affected-histogram
name="DataReductionProxy.HeaderTamperedHTTPS_Via_Missing"/>
</histogram_suffixes>
<histogram_suffixes name="DataReductionProxyBypassedBytes" separator=".">
<suffix name="SSL" label="Bypass due to SSL"/>
<suffix name="LocalBypassRules"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment