blob: b4021fcc8c025c83bbfccfb99a7a7ec7edfadef7 [file] [log] [blame]
// 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_