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

Side by Side Diff: components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect.cc

Issue 338483002: Chrome Participated Tamper Detect (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 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 unified diff | Download patch
OLDNEW
(Empty)
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 #include <string.h>
6 #include <algorithm>
7 #include <vector>
8
9 #include "base/base64.h"
10 #include "base/md5.h"
11 #include "base/metrics/sparse_histogram.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "components/data_reduction_proxy/browser/data_reduction_proxy_tamper_de tect.h"
14
15 #include "net/android/network_library.h"
16 #include "net/http/http_request_headers.h"
17 #include "net/http/http_util.h"
18
19 std::vector<std::string> GetHeaderValues(
20 const net::HttpResponseHeaders* headers, const std::string header_field) {
21 std::vector<std::string> values;
22 std::string value;
23 void* iter = NULL;
24 while (headers->EnumerateHeader(&iter, header_field, &value)) {
25 values.push_back(value);
26 }
27 return values;
28 }
29
30 std::string ValuesToSortedString(std::vector<std::string> &values) {
31 std::string aggregated_header = "";
32
33 std::sort(values.begin(), values.end());
34 for (size_t i = 0; i < values.size(); ++i)
35 aggregated_header += values[i] + ",";
36 return aggregated_header;
37 }
38
39 std::string GetMD5(const std::string input) {
40 base::MD5Context context;
41 base::MD5Init(&context);
42 base::MD5Update(&context, input);
43 base::MD5Digest new_digest;
44 base::MD5Final(&new_digest, &context);
45 return std::string((char*)new_digest.a, 16);
46 }
47
48 namespace data_reduction_proxy {
49
50 bool CheckHeaderChromeProxy(const std::string f1,
bolian 2014/06/25 18:55:56 I think it is better to return true in case of pos
xingx 2014/06/25 20:55:43 Done.
51 const net::HttpResponseHeaders* headers) {
52 // I call fingerprint from FW, received_fingerprint; the fingerprint
53 // generated from contents is called actual_fingerprint
54 std::string received_f1;
55 if (!base::Base64Decode(f1, &received_f1)) {
56 LOG(WARNING) << "Xing f1 base64 decode fails"; // remove later
57 return true;
58 }
59
60 // need to get all the values of Chrome-Proxy, remove value fp=xxx,
61 // and calculate hash value
62 std::vector<std::string> values = GetHeaderValues(headers, "Chrome-Proxy");
63
64 for (size_t i = 0; i < values.size(); ++i)
65 if (values[i].find("fp=") == 0) {
66 values.erase(values.begin() + i);
67 break;
68 }
69
70 // from vector of values of "Chrome-Proxy", forma a string and
71 // calculate the MD5 value on the string
72 std::string actual_f1 = GetMD5(ValuesToSortedString(values));
73
74 return received_f1.compare(actual_f1) == 0;
75 }
76
77 bool CheckHeaderVia(const std::string f2,
78 const net::HttpResponseHeaders* headers) {
79
80 // right now we get f2 value from FW, we may remove this later
81 // since for FW's f2 value, it should always be 0
82
83 std::vector<std::string> vias = GetHeaderValues(headers, "via");
84
85 // exist_chrome represents whether there is Chrome proxy
86 // in Via header;
87 // exist_hidden represents whether there is middlebox between
88 // FW and phone.
89 //bool exist_chrome = false;
90 bool exist_hidden = false;
91 for (int i = vias.size() - 1; i >= 0; --i)
92 if (vias[i].find("Chrome") != std::string::npos) {
93 // exist_chrome = true;
94 exist_hidden = (i < (int)(vias.size() - 1));
95 break;
96 }
97
98 return !exist_hidden;
99 }
100
101 bool CheckHeaderOtherHeaders(const std::string f3,
102 const net::HttpResponseHeaders* headers) {
103 std::string received_f3;
104
105 // f3 format:
106 // f3 = [base64fingerprint]:header_name1:header_namer2:...
107 net::HttpUtil::ValuesIterator it(f3.begin(), f3.end(), ':');
108 if (!(it.GetNext() && base::Base64Decode(
109 std::string(it.value_begin(), it.value_end()),
110 &received_f3))) {
111 LOG(WARNING) << "Xing f3 base64 decode fails";
112 return true;
113 }
114
115 // get header value for each header specified in f3
116 std::string header_values = "";
117 while (it.GetNext()) {
118 std::vector<std::string> values = GetHeaderValues(headers,
119 std::string(it.value_begin(),
120 it.value_end()));
121 header_values += ValuesToSortedString(values) + ";";
122 }
123
124 // calculate actual_f3
125 std::string actual_f3 = GetMD5(header_values);
126
127 return received_f3.compare(actual_f3) == 0;
128 }
129
130 bool CheckHeaderContentLength(const std::string f4,
131 const net::HttpResponseHeaders* headers,
132 std::string* mime_type) {
133 bool equal = true;
134 // if content_length from FW is not empty, check;
135 // otherwise, pass.
136 if (f4.size()) {
137 int received_content_length, actual_content_length;
138 if (!base::StringToInt(f4, &received_content_length))
139 return true;
140
141 std::string actual_content_length_;
142 if (headers->GetNormalizedHeader("Content-Length",
143 &actual_content_length_)) {
144 if (!base::StringToInt(actual_content_length_, &actual_content_length))
145 return true;
146 // equal marks whether received length == length sent by FW
147 equal = (received_content_length == actual_content_length);
148 }
149 }
150
151 if (!equal)
152 headers->GetMimeType(mime_type);
153 LOG(WARNING) << "xing type "<<*mime_type;
154 return equal;
155 }
156
157 void CheckResponseFingerprint(const net::HttpResponseHeaders* headers,
158 const bool is_secure_scheme)
159 {
160 // schemeIsSecure, we may need to change name, it means it's default
161 // FW on HTTPS or fallback FW on HTTP
162
163 // put values of Chrome-Proxy into a vector, check if it has a "fp=" value
164 std::vector<std::string> values = GetHeaderValues(headers, "Chrome-Proxy");
165
166 // enumerate and check if we see "fp=" value
167 int fingerprint_index = -1;
168 for (size_t i=0; i<values.size(); ++i) {
169 if (values[i].find("fp=") == 0) {
170 fingerprint_index = i;
171 break;
172 }
173 }
174
175 if (fingerprint_index == -1)
176 return;
177
178 // delimiter "|", separate fp= string: fp=f1|f2|f3|f4
179 net::HttpUtil::ValuesIterator it(values[fingerprint_index].begin() + 3,
180 values[fingerprint_index].end(), '|');
181
182 // we found "fp=" value, need to check fingerprint, first get carrier ID
183 unsigned mcc_mnc = 0;
184 base::StringToUint(net::android::GetTelephonyNetworkOperator(), &mcc_mnc);
185
186 // log total number for tamper detect
187 UMA_HISTOGRAM_SPARSE_SLOWLY(
188 is_secure_scheme ?
189 "DataReductionProxy.HTTPSHeaderTampereDetected" :
190 "DataReductionProxy.HTTPHeaderTampereDetected",
191 mcc_mnc);
192
193
194 // check fingerprint one by one
195 if (!it.GetNext()) return;
196 if (!CheckHeaderChromeProxy(std::string(it.value_begin(), it.value_end()),
197 headers)) {
198 // need to check if it's HTTP or HTTPS
199 UMA_HISTOGRAM_SPARSE_SLOWLY(
200 is_secure_scheme ?
201 "DataReductionProxy.HTTPSHeaderTampered_ChromeProxy" :
202 "DataReductionProxy.HTTPHeaderTampered_ChromeProxy",
203 mcc_mnc);
204
205 LOG(WARNING)<<"Xing f1 not equal";
206 }
207
208 if (!it.GetNext()) return;
209 if (!CheckHeaderVia(std::string(it.value_begin(), it.value_end()),
210 headers)) {
211 UMA_HISTOGRAM_SPARSE_SLOWLY(
212 is_secure_scheme ?
213 "DataReductionProxy.HTTPSHeaderTampered_Via" :
214 "DataReductionProxy.HTTPHeaderTampered_Via",
215 mcc_mnc);
216
217 LOG(WARNING)<<"Xing f2 not equal";
218 }
219
220 if (!it.GetNext()) return;
221 if (!CheckHeaderOtherHeaders(std::string(it.value_begin(), it.value_end()),
222 headers)) {
223 UMA_HISTOGRAM_SPARSE_SLOWLY(
224 is_secure_scheme ?
225 "DataReductionProxy.HTTPSHeaderTampered_OtherHeaders" :
226 "DataReductionProxy.HTTPHeaderTampered_OtherHeaders",
227 mcc_mnc);
228 LOG(WARNING)<<"Xing f3 not equal";
229 }
230
231 std::string mime_type;
232 if (!it.GetNext()) return;
233 if (!CheckHeaderContentLength(std::string(it.value_begin(), it.value_end()),
234 headers, &mime_type)) {
235 UMA_HISTOGRAM_SPARSE_SLOWLY(
236 is_secure_scheme ?
237 "DataReductionProxy.HTTPSHeaderTampered_ContentLength" :
238 "DataReductionProxy.HTTPHeaderTampered_ContentLength",
239 mcc_mnc);
240
241 if (mime_type.compare("text/javascript") == 0 ||
242 mime_type.compare("application/x-javascript") == 0 ||
243 mime_type.compare("application/javascript") == 0) {
244 UMA_HISTOGRAM_SPARSE_SLOWLY(
245 is_secure_scheme ?
246 "DataReductionProxy.HTTPSHeaderTampered_ContentLength_JS" :
247 "DataReductionProxy.HTTPHeaderTampered_ContentLength_JS",
248 mcc_mnc);
249
250 LOG(WARNING) << "Xing mimetype JS";
251 }
252 else if (mime_type.compare("text/css") == 0) {
253 UMA_HISTOGRAM_SPARSE_SLOWLY(
254 is_secure_scheme ?
255 "DataReductionProxy.HTTPSHeaderTampered_ContentLength_CSS" :
256 "DataReductionProxy.HTTPHeaderTampered_ContentLength_CSS",
257 mcc_mnc);
258
259 LOG(WARNING) << "Xing mimetype CSS";
260 }
261 else if (mime_type.find("image") == 0) {
262 UMA_HISTOGRAM_SPARSE_SLOWLY(
263 is_secure_scheme ?
264 "DataReductionProxy.HTTPSHeaderTampered_ContentLength_Image" :
265 "DataReductionProxy.HTTPHeaderTampered_ContentLength_Image",
266 mcc_mnc);
267
268 LOG(WARNING) << "Xing mimetype Image";
269 }
270 else {
271 UMA_HISTOGRAM_SPARSE_SLOWLY(
272 is_secure_scheme ?
273 "DataReductionProxy.HTTPSHeaderTampered_ContentLength_Other" :
274 "DataReductionProxy.HTTPHeaderTampered_ContentLength_Other",
275 mcc_mnc);
276
277 LOG(WARNING) << "Xing mimetype Other";
278 }
279 LOG(WARNING)<<"Xing f4 not equal";
280 }
281 }
282
283 } // namespace data_reduction_proxy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698