Skip to content

Commit 1067fc7

Browse files
authored
Add guide about IP address (#134)
1 parent 7a5ec16 commit 1067fc7

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

website/content/guide/ip-address.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
+++
2+
title = "IP Address"
3+
description = "IP address handling in Echo"
4+
[menu.main]
5+
name = "IP Address"
6+
parent = "guide"
7+
+++
8+
9+
IP address plays fundamental role in HTTP; it's used for access control, auditting, geo-based access analysis and more.
10+
Echo provides handy method [`Context#RealIP()`](https://godoc.org/github.com/labstack/echo#Context) for that.
11+
12+
However, it is not trivial to retrieve the _real_ IP address from requests especially when you put L7 proxies before the application.
13+
In such situation, _real_ IP needs to be relayed on HTTP layer from proxies to your app, but you must not trust HTTP headers unconditionally.
14+
Otherwise you might give someone a chance of deceiving you. **A security risk!**
15+
16+
To retrieve IP address reliably/securely, you must let your application be aware of the entire architecture of your infrastructrure.
17+
In Echo, this can be done by configuring `Echo#IPExtractor` appropriately.
18+
This guides show you why and how.
19+
20+
> Note: if you dont' set `Echo#IPExtractor` explicitly, Echo fallback to legacy behavior, which is not a good choice.
21+
22+
Let's start from two questions to know the right direction:
23+
24+
1. Do you put any HTTP (L7) proxy in front of the application?
25+
- It includes both cloud solutions (such as AWS ALB or GCP HTTP LB) and OSS ones (such as Nginx, Envoy or Istio ingress gateway).
26+
2. If yes, what HTTP header do your proxies use to pass client IP to the application?
27+
28+
## Case 1. With no proxy
29+
30+
If you put no proxy (e.g.: directory facing to the internet), all you need to (and have to) see is IP address from network layer.
31+
Any HTTP header is untrustable because the clients have full control what headers to be set.
32+
33+
In this case, use `echo.ExtractIPDirect()`.
34+
35+
```go
36+
e.IPExtractor = echo.ExtractIPDirect()
37+
```
38+
39+
## Case 2. With proxies using `X-Forwarded-For` header
40+
41+
[`X-Forwared-For` (XFF)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) is the popular header to relay clients' IP addresses.
42+
At each hop on the proxies, they append the request IP address at the end of the header.
43+
44+
Following example diagram illustrates this behavior.
45+
46+
```text
47+
┌──────────┐ ┌──────────┐ ┌──────────┐
48+
───────────>│ Proxy 1 │───────────>│ Proxy 2 │───────────>│ Your app │
49+
│ (IP: b) │ │ (IP: c) │ │ │
50+
└──────────┘ └──────────┘ └──────────┘
51+
52+
Case 1.
53+
XFF: "" "a" "a, b"
54+
~~~~~~
55+
Case 2.
56+
XFF: "x" "x, a" "x, a, b"
57+
~~~~~~~~~
58+
↑ What your app will see
59+
```
60+
61+
In this case, use **first _untrustable_ IP reading from right**. Never use first one reading from left, as it is configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructre". In above example, if `b` and `c` are trustable, the IP address of the client is `a` for both cases, never be `x`.
62+
63+
In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`.
64+
65+
```go
66+
e.IPExtractor = echo.ExtractIPFromXFFHeader()
67+
```
68+
69+
By default, it trusts internal IP addresses (loopback, link-local unicast, private-use and unique local address from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and [RFC4193](https://tools.ietf.org/html/rfc4193)). To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
70+
71+
E.g.:
72+
73+
```go
74+
e.IPExtractor = echo.ExtractIPFromXFFHeader(
75+
TrustLinkLocal(false),
76+
TrustIPRanges(lbIPRange),
77+
)
78+
```
79+
80+
- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
81+
82+
## Case 3. With proxies using `X-Real-IP` header
83+
84+
`X-Real-IP` is another HTTP header to relay clients' IP addresses, but it carries only one address unlike XFF.
85+
86+
If your proxies set this header, use `ExtractIPFromRealIPHeader(...TrustOption)`.
87+
88+
```go
89+
e.IPExtractor = echo.ExtractIPFromRealIPHeader()
90+
```
91+
92+
Again, it trusts internal IP addresses by default (loopback, link-local unicast, private-use and unique local address from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and [RFC4193](https://tools.ietf.org/html/rfc4193)). To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
93+
94+
- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
95+
96+
> **Never forget** to configure the outermost proxy (i.e.; at the edge of your infrastructure) **not to pass through incoming headers**.
97+
> Otherwise there is a chance of fraud, as it is what clients can control.
98+
99+
## About default behavior
100+
101+
In default behavior, Echo sees all of first XFF header, X-Real-IP header and IP from network layer.
102+
103+
As you might already notice, after reading this article, this is not good.
104+
Sole reason this is default is just backward compatibility.

0 commit comments

Comments
 (0)