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