1 // Copyright 2019 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 "services/network/public/cpp/header_util.h"
6
7 #include "base/strings/string_util.h"
8 #include "net/http/http_request_headers.h"
9
10 namespace network {
11
12 namespace {
13
14 // Headers that consumers are not trusted to set. All "Proxy-" prefixed messages
15 // are blocked inline. The"Authorization" auth header is deliberately not
16 // included, since OAuth requires websites be able to set it directly. These are
17 // a subset of headers forbidden by the fetch spec.
18 //
19 // This list has some values in common with
20 // https://fetch.spec.whatwg.org/#forbidden-header-name, but excludes some
21 // values that are still set by the caller in Chrome.
22 const char* kUnsafeHeaders[] = {
23 // This is determined by the upload body and set by net/. A consumer
24 // overriding that could allow for Bad Things.
25 net::HttpRequestHeaders::kContentLength,
26
27 // Disallow setting the Host header because it can conflict with specified
28 // URL and logic related to isolating sites.
29 net::HttpRequestHeaders::kHost,
30
31 // Trailers are not supported.
32 "Trailer", "Te",
33
34 // Websockets use a different API.
35 "Upgrade",
36
37 // Obsolete header, and network stack manages headers itself.
38 "Cookie2",
39
40 // Not supported by net/.
41 "Keep-Alive",
42
43 // Forbidden by the fetch spec.
44 net::HttpRequestHeaders::kTransferEncoding,
45
46 // TODO(mmenke): Figure out what to do about the remaining headers:
47 // Connection, Cookie, Date, Expect, Referer, Via.
48 };
49
50 // Headers that consumers are currently allowed to set, with the exception of
51 // certain values could cause problems.
52 // TODO(mmenke): Gather stats on these, and see if these headers can be banned
53 // outright instead.
54 const struct {
55 const char* name;
56 const char* value;
57 } kUnsafeHeaderValues[] = {
58 // Websockets use a different API.
59 {net::HttpRequestHeaders::kConnection, "Upgrade"},
60 };
61
62 } // namespace
63
IsRequestHeaderSafe(const base::StringPiece & key,const base::StringPiece & value)64 bool IsRequestHeaderSafe(const base::StringPiece& key,
65 const base::StringPiece& value) {
66 for (const auto* header : kUnsafeHeaders) {
67 if (base::EqualsCaseInsensitiveASCII(header, key))
68 return false;
69 }
70
71 for (const auto& header : kUnsafeHeaderValues) {
72 if (base::EqualsCaseInsensitiveASCII(header.name, key) &&
73 base::EqualsCaseInsensitiveASCII(header.value, value)) {
74 return false;
75 }
76 }
77
78 // Proxy headers are destined for the proxy, so shouldn't be set by callers.
79 if (base::StartsWith(key, "Proxy-", base::CompareCase::INSENSITIVE_ASCII))
80 return false;
81
82 return true;
83 }
84
AreRequestHeadersSafe(const net::HttpRequestHeaders & request_headers)85 bool AreRequestHeadersSafe(const net::HttpRequestHeaders& request_headers) {
86 net::HttpRequestHeaders::Iterator it(request_headers);
87
88 while (it.GetNext()) {
89 if (!IsRequestHeaderSafe(it.name(), it.value()))
90 return false;
91 }
92
93 return true;
94 }
95
96 } // namespace network
97