podman

Форк
0
120 строк · 4.5 Кб
1
package handlers
2

3
import (
4
	"net/http"
5
	"regexp"
6
	"strings"
7
)
8

9
var (
10
	// De-facto standard header keys.
11
	xForwardedFor    = http.CanonicalHeaderKey("X-Forwarded-For")
12
	xForwardedHost   = http.CanonicalHeaderKey("X-Forwarded-Host")
13
	xForwardedProto  = http.CanonicalHeaderKey("X-Forwarded-Proto")
14
	xForwardedScheme = http.CanonicalHeaderKey("X-Forwarded-Scheme")
15
	xRealIP          = http.CanonicalHeaderKey("X-Real-IP")
16
)
17

18
var (
19
	// RFC7239 defines a new "Forwarded: " header designed to replace the
20
	// existing use of X-Forwarded-* headers.
21
	// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43.
22
	forwarded = http.CanonicalHeaderKey("Forwarded")
23
	// Allows for a sub-match of the first value after 'for=' to the next
24
	// comma, semi-colon or space. The match is case-insensitive.
25
	forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`)
26
	// Allows for a sub-match for the first instance of scheme (http|https)
27
	// prefixed by 'proto='. The match is case-insensitive.
28
	protoRegex = regexp.MustCompile(`(?i)(?:proto=)(https|http)`)
29
)
30

31
// ProxyHeaders inspects common reverse proxy headers and sets the corresponding
32
// fields in the HTTP request struct. These are X-Forwarded-For and X-Real-IP
33
// for the remote (client) IP address, X-Forwarded-Proto or X-Forwarded-Scheme
34
// for the scheme (http|https), X-Forwarded-Host for the host and the RFC7239
35
// Forwarded header, which may include both client IPs and schemes.
36
//
37
// NOTE: This middleware should only be used when behind a reverse
38
// proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are
39
// configured not to) strip these headers from client requests, or where these
40
// headers are accepted "as is" from a remote client (e.g. when Go is not behind
41
// a proxy), can manifest as a vulnerability if your application uses these
42
// headers for validating the 'trustworthiness' of a request.
43
func ProxyHeaders(h http.Handler) http.Handler {
44
	fn := func(w http.ResponseWriter, r *http.Request) {
45
		// Set the remote IP with the value passed from the proxy.
46
		if fwd := getIP(r); fwd != "" {
47
			r.RemoteAddr = fwd
48
		}
49

50
		// Set the scheme (proto) with the value passed from the proxy.
51
		if scheme := getScheme(r); scheme != "" {
52
			r.URL.Scheme = scheme
53
		}
54
		// Set the host with the value passed by the proxy
55
		if r.Header.Get(xForwardedHost) != "" {
56
			r.Host = r.Header.Get(xForwardedHost)
57
		}
58
		// Call the next handler in the chain.
59
		h.ServeHTTP(w, r)
60
	}
61

62
	return http.HandlerFunc(fn)
63
}
64

65
// getIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239
66
// Forwarded headers (in that order).
67
func getIP(r *http.Request) string {
68
	var addr string
69

70
	switch {
71
	case r.Header.Get(xForwardedFor) != "":
72
		fwd := r.Header.Get(xForwardedFor)
73
		// Only grab the first (client) address. Note that '192.168.0.1,
74
		// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
75
		// the first may represent forwarding proxies earlier in the chain.
76
		s := strings.Index(fwd, ", ")
77
		if s == -1 {
78
			s = len(fwd)
79
		}
80
		addr = fwd[:s]
81
	case r.Header.Get(xRealIP) != "":
82
		addr = r.Header.Get(xRealIP)
83
	case r.Header.Get(forwarded) != "":
84
		// match should contain at least two elements if the protocol was
85
		// specified in the Forwarded header. The first element will always be
86
		// the 'for=' capture, which we ignore. In the case of multiple IP
87
		// addresses (for=8.8.8.8, 8.8.4.4,172.16.1.20 is valid) we only
88
		// extract the first, which should be the client IP.
89
		if match := forRegex.FindStringSubmatch(r.Header.Get(forwarded)); len(match) > 1 {
90
			// IPv6 addresses in Forwarded headers are quoted-strings. We strip
91
			// these quotes.
92
			addr = strings.Trim(match[1], `"`)
93
		}
94
	}
95

96
	return addr
97
}
98

99
// getScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239
100
// Forwarded headers (in that order).
101
func getScheme(r *http.Request) string {
102
	var scheme string
103

104
	// Retrieve the scheme from X-Forwarded-Proto.
105
	if proto := r.Header.Get(xForwardedProto); proto != "" {
106
		scheme = strings.ToLower(proto)
107
	} else if proto = r.Header.Get(xForwardedScheme); proto != "" {
108
		scheme = strings.ToLower(proto)
109
	} else if proto = r.Header.Get(forwarded); proto != "" {
110
		// match should contain at least two elements if the protocol was
111
		// specified in the Forwarded header. The first element will always be
112
		// the 'proto=' capture, which we ignore. In the case of multiple proto
113
		// parameters (invalid) we only extract the first.
114
		if match := protoRegex.FindStringSubmatch(proto); len(match) > 1 {
115
			scheme = strings.ToLower(match[1])
116
		}
117
	}
118

119
	return scheme
120
}
121

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.