Chromium Code Reviews| Index: components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect.cc |
| diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ec8e83da504f475df0389979da6eadf0078a1daf |
| --- /dev/null |
| +++ b/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect.cc |
| @@ -0,0 +1,435 @@ |
| +// 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, where we want to detect |
|
bengr
2014/07/11 18:22:45
This comment should be moved to the .h.
xingx
2014/07/15 04:51:33
Done.
|
| +// whether there are middleboxes and whether they are tampering the response |
| +// which maybe break correct communication and data transfer between Chrome |
| +// and data reduction proxy. |
| +// |
| +// A high-level description of our tamper detection process works in two steps: |
| +// 1. Data reduction proxy selects the requests we want to detect tamper; |
|
bengr
2014/07/11 18:22:46
The data...
xingx
2014/07/15 04:51:32
Done.
|
| +// for the selected ones, data reduction proxy generates a series of |
|
bengr
2014/07/11 18:22:47
the data reduction...
xingx
2014/07/15 04:51:34
Done.
|
| +// fingerprints of the response, and append them to the Chrome-Proxy header; |
|
bengr
2014/07/11 18:22:46
of -> for
appends it
xingx
2014/07/15 04:51:34
Done.
|
| +// 2. At Chrome client side, once it sees such fingerprints, it uses the |
|
bengr
2014/07/11 18:22:46
When Chrome sees such fingerprints in response hea
xingx
2014/07/15 04:51:33
Done.
|
| +// same method of data reduction proxy to generate the fingerprints on |
|
bengr
2014/07/11 18:22:44
of --> as the
remove "on the response it receives
xingx
2014/07/15 04:51:33
Done.
|
| +// the response it receives, compare it to the result on the response |
| +// data reduction proxy sends, i.e., the attached fingerprints in |
| +// Chrome-Proxy header, to see if they are identical and report to UMA if |
| +// there is any tamper detected. |
| +// |
| +// Right now we have 4 fingerprints (listed below). Chrome first check the |
|
bengr
2014/07/11 18:22:47
Right now we --> Four fingerprints are defined (li
xingx
2014/07/15 04:51:33
Done.
|
| +// fingerprint of Chrome-Proxy header. If Chrome-Proxy header has been |
| +// tampered, then other fingerprints would not be checked; if not, Chrome |
|
bengr
2014/07/11 18:22:46
This is Chromium code too.
In general you don't h
xingx
2014/07/15 04:51:34
Done.
|
| +// parses the rest of the fingerprints and check whether there is tampering |
|
bengr
2014/07/11 18:22:47
checks
xingx
2014/07/15 04:51:33
Done.
|
| +// on each of them. |
| +// |
| +// 1. Chrome-Proxy header |
| +// whether values of Chrome-Proxy have been tampered; |
| +// 2. Via header |
| +// whether there are middleboxes between Chrome and data reduction proxy; |
| +// 3. Some other headers |
| +// whether the values of a list of headers have been tampered; |
| +// 4. Content-Length header |
| +// whether the value of Content-Length is different to what data reduction |
| +// proxy sends, which indicates that the response body has been tampered. |
| +// |
| +// Chrome reports tamper or not information for each fingerprint to UMA. In |
|
bengr
2014/07/11 18:22:46
Up above you seem to suggest that UMA is only coll
xingx
2014/07/15 04:51:34
Done.
|
| +// general, Chrome reports the number of tampers for each fingerprint on |
| +// different carriers, as well as total number of tamper detection handled. |
| +// The only special case is the 4th fingerprint, Content-Length, which we have |
| +// another dimension, MIME types, Chrome reports the tamper on different MIME |
| +// type independently. |
| + |
| + |
| +#include <string.h> |
| +#include <algorithm> |
|
bengr
2014/07/11 18:22:47
alphabetize
xingx
2014/07/15 04:51:33
Done.
|
| +#include <vector> |
| + |
| +#include "base/base64.h" |
| +#include "base/md5.h" |
| +#include "base/metrics/histogram.h" |
| +#include "base/metrics/sparse_histogram.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detect.h" |
| + |
|
bengr
2014/07/11 18:22:44
remove the blank line
xingx
2014/07/15 04:51:34
Done.
|
| +#include "net/android/network_library.h" |
| +#include "net/http/http_request_headers.h" |
| +#include "net/http/http_util.h" |
| + |
| +// Macro for UMA report. First report to either |https_histogram| or |
|
bengr
2014/07/11 18:22:45
report -> reporting
xingx
2014/07/15 04:51:34
Done.
|
| +// |http_histogram| depends on |scheme_is_https|, with carrier ID as bucket |
|
bengr
2014/07/11 18:22:46
depends -> depending
xingx
2014/07/15 04:51:33
Done.
|
| +// |mcc_mnc_|. Then report to http(s)_histogram_Total, which counts the total |
|
bengr
2014/07/11 18:22:45
carrier_id_
bengr
2014/07/11 18:22:46
Is that the name of the histogram? Clarify.
xingx
2014/07/15 04:51:35
Done.
|
| +// number. |
| +#define UMA_REPORT(scheme_is_https, http_histogram, https_histogram, mcc_mnc) \ |
|
bengr
2014/07/11 18:22:44
Why is this a macro. Make this a function.
xingx
2014/07/15 04:51:33
Because it is only 1 line of code and occurs a lot
|
| + do { \ |
| + if (scheme_is_https) { \ |
| + UMA_HISTOGRAM_SPARSE_SLOWLY(https_histogram, mcc_mnc); \ |
| + UMA_HISTOGRAM_COUNTS(https_histogram "_Total", 1); \ |
| + } else { \ |
| + UMA_HISTOGRAM_SPARSE_SLOWLY(http_histogram, mcc_mnc); \ |
| + UMA_HISTOGRAM_COUNTS(http_histogram "_Total", 1); \ |
| + }\ |
| + } while (0) |
| + |
| +namespace data_reduction_proxy { |
| + |
| +namespace { |
|
bengr
2014/07/11 18:22:45
I see no reason for this anonymous namespace to be
xingx
2014/07/15 04:51:35
Done.
|
| +// Two fingerprints will be added to Chrome-Proxy header. One starts with |
|
bengr
2014/07/11 18:22:47
I thought you were checking 4 things, not 2. Expla
xingx
2014/07/15 04:51:34
Done.
|
| +// |kTamperDetectFingerprintChromeProxy|, which is the fingerprint for the |
| +// Chrome-Proxy header. The other one starts with |kTamperDetectFingerprint|, |
| +// which includes all other fingerprints. |
| +const char kTamperDetectFingerprints[] = "fp="; |
| +const char kTamperDetectFingerprintChromeProxy[] = "cp="; |
| + |
| +// Fingerprint |kTamperDetectFingerprint| contains multiple |
| +// fingerprints, each starts with a tag followed by "=" and its fingerprint |
| +// value. Three fingerprints and their respective tags are defined below. |
| +const char kTamperDetectFingerprintVia[] = "via"; |
| +const char kTamperDetectFingerprintOther[] = "oh"; |
| +const char kTamperDetectFingerprintContengLength[] = "cl"; |
| + |
| +} // namespace |
| + |
| +void DataReductionProxyTamperDetect::CheckResponseFingerprint( |
|
bengr
2014/07/11 18:22:47
add: "// static" above this line.
xingx
2014/07/15 04:51:35
Done.
|
| + const net::HttpResponseHeaders* headers, |
| + const bool is_secure_scheme) |
| +{ |
| + std::vector<std::string> values = DataReductionProxyTamperDetect:: |
|
bengr
2014/07/11 18:22:45
You don't need the DataReductionProxyTamperDetect:
xingx
2014/07/15 04:51:34
Done.
|
| + GetHeaderValues(headers, "Chrome-Proxy"); |
| + |
| + // |chrome_proxy_fingerprint| holds the value of fingerprint of |
| + // Chrome-Proxy header. |
| + // |other_fingerprints| holds the value of other fingerprints. |
| + std::string chrome_proxy_fingerprint, other_fingerprints; |
| + |
| + // Check if there are fingerprints (and thus need to detect tamper). |
|
bengr
2014/07/11 18:22:47
tampering
xingx
2014/07/15 04:51:33
Done.
|
| + if (!GetTamperDetectFingerprints(&values, |
|
bengr
2014/07/11 18:22:46
rename: GetTamperDetectionFingerprints, or just Ge
xingx
2014/07/15 04:51:35
Done.
|
| + &chrome_proxy_fingerprint, |
| + &other_fingerprints)) |
| + return; |
| + |
| + // Found tamper detect request field. |
|
bengr
2014/07/11 18:22:46
detection
xingx
2014/07/15 04:51:35
Done.
|
| + // Get carrier ID. |
| + unsigned mcc_mnc = 0; |
|
bengr
2014/07/11 18:22:46
carrier_id
xingx
2014/07/15 04:51:35
Done.
|
| + base::StringToUint(net::android::GetTelephonyNetworkOperator(), &mcc_mnc); |
|
bengr
2014/07/11 18:22:45
What do you do on other platforms? Will this even
|
| + |
| + DataReductionProxyTamperDetect tamper_detect(headers, is_secure_scheme, |
|
bengr
2014/07/11 18:22:45
put each param on its own line if they don't all f
xingx
2014/07/15 04:51:33
Done.
|
| + mcc_mnc, &values); |
| + |
| + // Check if Chrome-Proxy header has been tampered. |
|
bengr
2014/07/11 18:22:46
if the Chrome-Proxy ... tampered with.
xingx
2014/07/15 04:51:34
Done.
|
| + if (tamper_detect.IsChromeProxyHeaderTampered(chrome_proxy_fingerprint)) { |
|
bengr
2014/07/11 18:22:46
rename tamper_detect as tamper_detection
xingx
2014/07/15 04:51:34
Done.
|
| + UMA_REPORT(is_secure_scheme, |
| + "DataReductionProxy.HTTPSHeaderTampered_ChromeProxy", |
| + "DataReductionProxy.HTTPHeaderTampered_ChromeProxy", |
| + mcc_mnc); |
| + return; |
| + } else |
|
bengr
2014/07/11 18:22:45
add curly braces
xingx
2014/07/15 04:51:35
Done.
|
| + UMA_REPORT(is_secure_scheme, |
| + "DataReductionProxy.HTTPSHeaderTamperDetection", |
| + "DataReductionProxy.HTTPHeaderTamperDetection", |
| + mcc_mnc); |
| + |
| + // Separate fingerprints from |other_fingerprints|. |
| + net::HttpUtil::ValuesIterator it(other_fingerprints.begin(), |
|
bengr
2014/07/11 18:22:45
put all the parameters on one line
xingx
2014/07/15 04:51:35
Done.
|
| + other_fingerprints.end(), '|'); |
| + |
| + // For each fingerprint, get its name |key| and the fingerprint value |value| |
|
bengr
2014/07/11 18:22:45
I think DataReductionProxyHeaders should have a fu
|
| + // from data reduction proxy. CheckReportFingerprint will handle the tamper |
| + // detect and corresponding UMA report. |
|
bengr
2014/07/11 18:22:47
detect --> detection
and report the corresponding
xingx
2014/07/15 04:51:35
Removed that two lines, codes explain it pretty mu
|
| + size_t delimiter_pos = std::string::npos; |
| + while (it.GetNext()) { |
|
bengr
2014/07/11 18:22:44
can't you use the same logic as in data_reduction_
|
| + delimiter_pos = it.value().find("="); |
| + if (delimiter_pos == std::string::npos) |
| + continue; |
| + std::string key = it.value().substr(0, delimiter_pos); |
| + std::string value = it.value().substr(delimiter_pos + 1); |
| + |
| + FingerprintCode fingerprint_code = tamper_detect.GetFingerprintCode(key); |
| + switch (fingerprint_code) { |
| + case VIA: |
| + if (tamper_detect.IsViaHeaderTampered(value)) |
| + tamper_detect.ReportViaHeaderTamperedUMA(); |
| + break; |
| + case OTHERHEADERS: |
| + if (tamper_detect.AreOtherHeadersTampered(value)) |
| + tamper_detect.ReportOtherHeadersTamperedUMA(); |
| + break; |
| + case CONTENTLENGTH: |
| + if (tamper_detect.IsContentLengthHeaderTampered(value)) |
| + tamper_detect.ReportContentLengthHeaderTamperedUMA(); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + } |
| + return; |
| +} |
| + |
| +// Initialize fingerprint code map. |
| +DataReductionProxyTamperDetect::DataReductionProxyTamperDetect( |
| + const net::HttpResponseHeaders* headers, const bool is_secure, |
| + const unsigned mcc_mnc, std::vector<std::string>* values) |
| + : response_headers_(headers), |
| + is_secure_scheme_(is_secure), |
| + mcc_mnc_(mcc_mnc), |
| + clean_chrome_proxy_header_values_(values) { |
| + fingperprint_tag_code_map_ = std::map<std::string, FingerprintCode>(); |
| + fingperprint_tag_code_map_[kTamperDetectFingerprintVia] = VIA; |
| + fingperprint_tag_code_map_[kTamperDetectFingerprintOther] = OTHERHEADERS; |
| + fingperprint_tag_code_map_[kTamperDetectFingerprintContengLength] = |
| + CONTENTLENGTH; |
| +}; |
| + |
| +DataReductionProxyTamperDetect::~DataReductionProxyTamperDetect() {}; |
| + |
| +// Check whether Chrome-Proxy header has been tampered. |
|
bengr
2014/07/11 18:22:46
tampered with.
bengr
2014/07/11 18:22:46
Checks whether the
xingx
2014/07/15 04:51:34
Done.
xingx
2014/07/15 04:51:35
Done.
|
| +// |fingerprint| is the fingerprint Chrome received from data reduction proxy, |
|
bengr
2014/07/11 18:22:45
remove "Chrome"
xingx
2014/07/15 04:51:34
Done.
|
| +// which is Base64 encoded. Decode it first. Calculate the hash value of |
|
bengr
2014/07/11 18:22:47
Calculates...
xingx
2014/07/15 04:51:33
Done.
|
| +// Chrome-Proxy header. Note that |clean_chrome_proxy_header_values__| holds |
| +// the values of Chrome-Proxy header with its own fingerprint removed, |
| +// so it's the correct values to be used to calculate fingerprint. |
| +// Compare calculated fingerprint to the fingerprint from data reduction proxy |
|
bengr
2014/07/11 18:22:46
Compares...
xingx
2014/07/15 04:51:34
Done.
|
| +// (the removed value) and see there is tamper detected. |
| +bool DataReductionProxyTamperDetect::IsChromeProxyHeaderTampered( |
| + const std::string& fingerprint) const { |
|
bengr
2014/07/11 18:22:46
indent only 4.
xingx
2014/07/15 04:51:34
Done.
|
| + std::string received_fingerprint; |
| + if (!base::Base64Decode(fingerprint, &received_fingerprint)) |
| + return true; |
| + // Calculate the MD5 hash value of Chrome-Proxy. |
| + std::string actual_fingerprint = GetMD5( |
| + ValuesToSortedString(*clean_chrome_proxy_header_values_)); |
|
bengr
2014/07/11 18:22:47
Where is memory allocated for this vector?
|
| + |
| + return received_fingerprint != actual_fingerprint; |
| +} |
| + |
| +// Check whether there are proxies/middleboxes between Chrome |
|
bengr
2014/07/11 18:22:44
Remove the first sentence and the word "Concretely
bengr
2014/07/11 18:22:45
Checks...
xingx
2014/07/15 04:51:33
Done.
xingx
2014/07/15 04:51:34
Done.
|
| +// and data reduction proxy. Concretely, it checks whether there are other |
|
bengr
2014/07/11 18:22:47
and the...
xingx
2014/07/15 04:51:35
removed.
|
| +// proxies/middleboxes' name after data reduction proxy's name in Via header. |
| +bool DataReductionProxyTamperDetect::IsViaHeaderTampered( |
| + const std::string& fingerprint) const { |
|
bengr
2014/07/11 18:22:45
indent only 4
xingx
2014/07/15 04:51:32
Done.
|
| + |
| + std::vector<std::string> vias = GetHeaderValues(response_headers_, "via"); |
|
bengr
2014/07/11 18:22:45
vias -> via_header_values
xingx
2014/07/15 04:51:34
Done.
|
| + |
| + // If there is no tag, then data reduction proxy's tag have been removed. |
|
bengr
2014/07/11 18:22:44
have -> has
bengr
2014/07/11 18:22:47
then the
xingx
2014/07/15 04:51:35
Done.
xingx
2014/07/15 04:51:35
Done.
|
| + if (vias.size() == 0) return true; |
|
bengr
2014/07/11 18:22:46
move the return to the next line.
xingx
2014/07/15 04:51:34
Done.
|
| + |
| + // Check whether the last proxy/middlebox is data reduction proxy or not. |
|
bengr
2014/07/11 18:22:45
is the
xingx
2014/07/15 04:51:34
Done.
|
| + bool seen_data_reduction_proxy = false; |
|
bengr
2014/07/11 18:22:44
seen_data_reduction_proxy -> in_via_header
xingx
2014/07/15 04:51:33
Done.
|
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDataReductionProxyViaValues); ++i) { |
| + if (vias[vias.size() - 1].find(kDataReductionProxyViaValues[i]) != |
| + std::string::npos) { |
| + seen_data_reduction_proxy = true; |
| + break; |
| + } |
| + } |
| + |
| + return !seen_data_reduction_proxy; |
|
bengr
2014/07/11 18:22:47
In general, you shouldn't do any header processing
|
| +} |
| + |
| +// Report Via header tamper detected. |
| +void DataReductionProxyTamperDetect::ReportViaHeaderTamperedUMA() const { |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_Via", |
| + "DataReductionProxy.HTTPHeaderTampered_Via", |
| + mcc_mnc_); |
| +} |
| + |
| +// Check whether values of a predefined list of headers have been tampered. |
| +// The format for |fingerprint| is: |
| +// [base64fingerprint]:header_name1:header_namer2:... |
| +// Firstly extract the header names in the |fingerprint|. |
| +// For each header, |
| +// 1) get all the values of such header; |
| +// 2) sort the values alphabetically; |
| +// 3) concatenate sorted values to a string and calculate MD5 hash on it. |
| +// Finally, compare whether it equals to the received fingerprint. |
| +bool DataReductionProxyTamperDetect::AreOtherHeadersTampered( |
| + const std::string& fingerprint) const { |
| + std::string received_fingerprint; |
| + |
| + // Fingerprint should never be empty. |
| + DCHECK(fingerprint.size()); |
| + |
| + net::HttpUtil::ValuesIterator it(fingerprint.begin(), |
| + fingerprint.end(), ':'); |
| + |
| + // Make sure there is [base64fingerprint] and it can be decoded. |
| + if (!(it.GetNext() && |
| + base::Base64Decode(std::string(it.value()), &received_fingerprint))) { |
| + NOTREACHED(); |
| + return true; |
| + } |
| + |
| + std::string header_values; |
| + // Enumerate the list of headers. |
| + while (it.GetNext()) { |
|
bengr
2014/07/11 18:22:47
This will start with the second fingerprint, becau
xingx
2014/07/15 04:51:33
Done.
|
| + // Get values of one header. |
| + std::vector<std::string> values = |
| + GetHeaderValues(response_headers_, it.value()); |
| + // Sort the values and concatenate them. |
| + header_values += ValuesToSortedString(values) + ";"; |
| + } |
| + |
| + // Calculate MD5 hash value on the concatenated string. |
| + std::string actual_fingerprint = GetMD5(header_values); |
| + |
| + return received_fingerprint != actual_fingerprint; |
| +} |
| + |
| +// Report other headers tamper detected. |
|
bengr
2014/07/11 18:22:46
Reports...
xingx
2014/07/15 04:51:33
Done.
|
| +void DataReductionProxyTamperDetect::ReportOtherHeadersTamperedUMA() const { |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_OtherHeaders", |
| + "DataReductionProxy.HTTPHeaderTampered_OtherHeaders", |
| + mcc_mnc_); |
| +} |
| + |
| + |
| +// For Content-Length tamper detection... |
|
bengr
2014/07/11 18:22:45
Use complete sentences.
xingx
2014/07/15 04:51:33
Done.
|
| +// Check whether the Content-Length value is different from what |
|
bengr
2014/07/11 18:22:47
Checks...
xingx
2014/07/15 04:51:32
Done.
|
| +// data reduction proxy sees. This is an indicator that the response body |
| +// have been modified. |
|
bengr
2014/07/11 18:22:47
Fill comments out to 80 characters.
xingx
2014/07/15 04:51:33
Done.
|
| +// It's modified only if we can decode Content-Length numbers at both end |
| +// and such two numbers are not equal. |
| +bool DataReductionProxyTamperDetect::IsContentLengthHeaderTampered( |
| + const std::string& fingerprint) const { |
|
bengr
2014/07/11 18:22:44
indent only 4
xingx
2014/07/15 04:51:35
Done.
|
| + int received_content_length, actual_content_length; |
| + // If Content-Length value from data reduction proxy is not available or |
| + // it cannot be converted to integer, pass. |
|
bengr
2014/07/11 18:22:45
to an
xingx
2014/07/15 04:51:33
Done.
|
| + if (base::StringToInt(fingerprint, &received_content_length)) { |
| + std::string actual_content_length_; |
| + // If there is Content-Length at Chrome client side is not available, pass. |
|
bengr
2014/07/11 18:22:46
We are on the client side.
xingx
2014/07/15 04:51:32
Done.
|
| + if (response_headers_->GetNormalizedHeader("Content-Length", |
| + &actual_content_length_)) { |
| + // If the Content-Length value cannot be converted to integer, |
| + // i.e., not valid, pass. |
| + if (!base::StringToInt(actual_content_length_, &actual_content_length)) |
| + return false; |
| + return received_content_length != actual_content_length; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +// Report Content-Length tamper detected. |
|
bengr
2014/07/11 18:22:47
Reports...
xingx
2014/07/15 04:51:33
Done.
|
| +// Get MIME type of the response and report to different UMA histogram. |
|
bengr
2014/07/11 18:22:45
Gets...
xingx
2014/07/15 04:51:33
Done.
|
| +// Right now MIME types contain JavaScript, CSS, Images, and others. |
| +void DataReductionProxyTamperDetect::ReportContentLengthHeaderTamperedUMA() |
| + const { |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_ContentLength", |
| + "DataReductionProxy.HTTPHeaderTampered_ContentLength", |
| + mcc_mnc_); |
| + |
| + // Get MIME type. |
| + std::string mime_type; |
| + response_headers_->GetMimeType(&mime_type); |
| + |
| + |
| + // Report tampered JavaScript. |
| + if (mime_type.compare("text/javascript") == 0 || |
| + mime_type.compare("application/x-javascript") == 0 || |
| + mime_type.compare("application/javascript") == 0) |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_ContentLength_JS", |
| + "DataReductionProxy.HTTPHeaderTampered_ContentLength_JS", |
| + mcc_mnc_); |
| + // Report tampered CSSs. |
| + else if (mime_type.compare("text/css") == 0) |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_ContentLength_CSS", |
| + "DataReductionProxy.HTTPHeaderTampered_ContentLength_CSS", |
| + mcc_mnc_); |
| + // Report tampered images. |
| + else if (mime_type.find("image") == 0) |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_ContentLength_Image", |
| + "DataReductionProxy.HTTPHeaderTampered_ContentLength_Image", |
| + mcc_mnc_); |
| + // Report tampered other MIME types. |
| + else |
| + UMA_REPORT(is_secure_scheme_, |
| + "DataReductionProxy.HTTPSHeaderTampered_ContentLength_Other", |
| + "DataReductionProxy.HTTPHeaderTampered_ContentLength_Other", |
| + mcc_mnc_); |
| +} |
| + |
| +DataReductionProxyTamperDetect::FingerprintCode |
| + DataReductionProxyTamperDetect::GetFingerprintCode( |
| + const std::string& tag) { |
| + std::map<std::string, DataReductionProxyTamperDetect::FingerprintCode> |
| + ::iterator it = fingperprint_tag_code_map_.find(tag); |
| + |
| + return it == fingperprint_tag_code_map_.end() ? NONEXIST : it->second; |
| +} |
| + |
| +// Enumerate the values of Chrome-Proxy header and check if there are |
| +// fingerprints of Chrome-Proxy header (kTamperDetectFingerprintChromeProxy) |
| +// and other fingerprints (kTamperDetectFingerprint). If there are, save them |
| +// accordingly and return true, otherwise return false. |
| +bool DataReductionProxyTamperDetect::GetTamperDetectFingerprints( |
| + std::vector<std::string>* values, |
| + std::string* chrome_proxy_fingerprint, |
| + std::string* other_fingerprints) { |
| + int tamper_detect_fingerprints_index = -1; |
| + |
| + size_t size = values->size(); |
| + for (size_t i = 0; i < size; ++i) { |
| + if ((*values)[i].find(kTamperDetectFingerprintChromeProxy) == 0) { |
| + tamper_detect_fingerprints_index = i; |
| + // Save Chrome-Proxy fingerprint. |
| + *chrome_proxy_fingerprint = (*values)[i].substr(strlen( |
| + kTamperDetectFingerprintChromeProxy)); |
| + } |
| + else if ((*values)[i].find(kTamperDetectFingerprints) == 0) { |
| + // Save other fingerprints. |
| + *other_fingerprints = (*values)[i].substr( |
| + strlen(kTamperDetectFingerprints)); |
| + } |
| + } |
| + |
| + if (tamper_detect_fingerprints_index == -1) |
| + return false; |
| + |
| + // Erase Chrome-Proxy's fingerprint from Chrome-Proxy header for |
| + // later fingerprint calculation. |
| + values->erase(values->begin() + tamper_detect_fingerprints_index); |
| + return true; |
| +} |
| + |
| +// Utility function. Sort the strings in |values| alphabetically, concatenate |
| +// them into a string. |
| +std::string DataReductionProxyTamperDetect::ValuesToSortedString( |
| + std::vector<std::string> &values) { |
| + std::string aggregated_values; |
| + |
| + std::sort(values.begin(), values.end()); |
| + for (size_t i = 0; i < values.size(); ++i) |
| + aggregated_values += values[i] + ","; |
| + return aggregated_values; |
| +} |
| + |
| +// Utility function. For a given string, calculate and return the MD5 hash |
| +// value of the string. |
| +std::string DataReductionProxyTamperDetect::GetMD5(const std::string &input) { |
| + base::MD5Digest digest; |
| + base::MD5Sum(input.c_str(), input.size(), &digest); |
| + return std::string((char*)digest.a, ARRAYSIZE_UNSAFE(digest.a)); |
| +} |
| + |
| +// Utility function. For a given |header_name|, get all its values and return |
| +// the vector contains all of the values. |
| +std::vector<std::string> DataReductionProxyTamperDetect::GetHeaderValues( |
| + const net::HttpResponseHeaders* headers, const std::string& header_name) { |
| + std::vector<std::string> values; |
| + std::string value; |
| + void* iter = NULL; |
| + while (headers->EnumerateHeader(&iter, header_name, &value)) { |
| + values.push_back(value); |
| + } |
| + return values; |
| +} |
| + |
| +} // namespace data_reduction_proxy |