Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 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.
      4 
      5 // This file implements the tamper detection logic, which detects whether
      6 // there are middleboxes and whether they are tampering with the response
      7 // which may break correct communication and data transfer between the Chromium
      8 // client and the data reduction proxy.
      9 //
     10 // At a high level, the tamper detection process works in two steps:
     11 // 1. The data reduction proxy selects a fraction of responses to analyze,
     12 //    generates a series of fingerprints for each, and appends them to the
     13 //    Chrome-Proxy response headers;
     14 // 2. The client re-generate the fingerprints using the same method as the
     15 //    proxy, compares them to the fingerprints in the response, and generates
     16 //    UMA. A response is considered to have been tampered with if the
     17 //    fingerprints do not match.
     18 //
     19 // Four fingerprints are generated by the data reduction proxy:
     20 // 1. Fingerprint of the Chrome-Proxy header, which is designed to check
     21 //    whether the Chrome-Proxy header has been modified or not;
     22 // 2. Fingerprint of the Via header, which is designed to check whether there
     23 //    are middleboxes between the Chromium client and the data reduction proxy;
     24 // 3. Fingerprint of a list of headers, which is designed to check whether the
     25 //    values of a list of headers (list is defined by the data reduction proxy)
     26 //    have been modified or deleted;
     27 // 4. Fingerprint of the Content-Length header, which is designed to check
     28 //    whether the response body has been modified or not (the code assumes that
     29 //    different Content-Length values indicate different response bodies).
     30 //
     31 // On the client side, the fingerprint of the Chrome-Proxy header will be
     32 // checked first. If the fingerprint indicates that the Chrome-Proxy header has
     33 // not been modified, then the other fingerprints will be considered to be
     34 // reliable and will be checked next; if not, then it's possible that the other
     35 // fingerprints have been tampered with and thus they will not be checked.
     36 // If middlebox removes all the fingerprints then such tampering will not be
     37 // detected.
     38 //
     39 // Detected tampering information will be reported to UMA. In general, for each
     40 // fingerprint, the client reports the number of responses that have been
     41 // tampered with for different carriers. For the fingerprint of the
     42 // Content-Length header, which indicates whether the response body has been
     43 // modified or not, the reports of tampering are separated by MIME type of the
     44 // response body.
     45 
     46 #ifndef COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_TAMPER_DETECTION_H_
     47 #define COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_TAMPER_DETECTION_H_
     48 
     49 #include <map>
     50 #include <string>
     51 #include <vector>
     52 
     53 #include "net/proxy/proxy_service.h"
     54 
     55 namespace net {
     56 class HttpResponseHeaders;
     57 }
     58 
     59 namespace data_reduction_proxy {
     60 
     61 // Detects if the response sent by the data reduction proxy has been modified
     62 // by intermediaries on the Web.
     63 class DataReductionProxyTamperDetection {
     64  public:
     65   // Checks if the response contains tamper detection fingerprints added by the
     66   // data reduction proxy, and determines if the response had been tampered
     67   // with if so. Results are reported to UMA. HTTP and HTTPS traffic are
     68   // reported separately, specified by |scheme_is_https|. Returns true if
     69   // the response has been tampered with.
     70   static bool DetectAndReport(const net::HttpResponseHeaders* headers,
     71                               bool scheme_is_https);
     72 
     73   // Tamper detection checks |response_headers|. Histogram events are reported
     74   // by |carrier_id|; |scheme_is_https| determines which histogram to report
     75   // (HTTP and HTTPS are reported separately).
     76   DataReductionProxyTamperDetection(
     77       const net::HttpResponseHeaders* response_headers,
     78       bool scheme_is_https,
     79       unsigned carrier_id);
     80 
     81   virtual ~DataReductionProxyTamperDetection();
     82 
     83  private:
     84   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     85                            TestFingerprintCommon);
     86   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     87                            ChromeProxy);
     88   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     89                            Via);
     90   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     91                            OtherHeaders);
     92   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     93                            ContentLength);
     94   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     95                            HeaderRemoving);
     96   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     97                            ValuesToSortedString);
     98   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
     99                            GetHeaderValues);
    100   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
    101                            DetectAndReport);
    102 
    103   // Returns the result of validating Chrome-Proxy header.
    104   bool ValidateChromeProxyHeader(const std::string& fingerprint) const;
    105 
    106   // Reports UMA for tampering of the Chrome-Proxy header.
    107   void ReportUMAforChromeProxyHeaderValidation() const;
    108 
    109   // Returns the result of validating the Via header. |has_chrome_proxy|
    110   // indicates that the data reduction proxy's Via header occurs or not.
    111   bool ValidateViaHeader(const std::string& fingerprint,
    112                          bool* has_chrome_proxy_via_header) const;
    113 
    114   // Reports UMA for tampering of the Via header.
    115   void ReportUMAforViaHeaderValidation(bool has_chrome_proxy_via_header) const;
    116 
    117   // Returns the result of validating a list of headers.
    118   bool ValidateOtherHeaders(const std::string& fingerprint) const;
    119 
    120   // Reports UMA for tampering of values of the list of headers.
    121   void ReportUMAforOtherHeadersValidation() const;
    122 
    123   // Returns the result of validating the Content-Length header.
    124   bool ValidateContentLengthHeader(const std::string& fingerprint) const;
    125 
    126   // Reports UMA for tampering of the Content-Length header.
    127   void ReportUMAforContentLengthHeaderValidation() const;
    128 
    129   // Returns a string representation of |values|.
    130   static std::string ValuesToSortedString(std::vector<std::string>* values);
    131 
    132   // Returns raw MD5 hash value for a given string |input|. It is different to
    133   // base::MD5String which is base16 encoded.
    134   static void GetMD5(const std::string& input, std::string* output);
    135 
    136   // Returns all the values of |header_name| of the response |headers| as a
    137   // vector. This function is used for values that need to be sorted later.
    138   static std::vector<std::string> GetHeaderValues(
    139       const net::HttpResponseHeaders* headers,
    140       const std::string& header_name);
    141 
    142   // Pointer to response headers.
    143   const net::HttpResponseHeaders* response_headers_;
    144 
    145   // If true, the connection to the data reduction proxy is over HTTPS;
    146   const bool scheme_is_https_;
    147 
    148   // Carrier ID: the numeric name of the current registered operator.
    149   const unsigned carrier_id_;
    150 
    151   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyTamperDetection);
    152 };
    153 
    154 }  // namespace data_reduction_proxy
    155 #endif  // COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_TAMPER_DETECTION_H_
    156