X-Forwarded-For, Forwarded, X-Real-IP and Nginx

2018 May 22
X-Forwarded-For

Http header X-Forwarded-For can be used to get the IP address of the REAL client, especially in a network with proxies and load balancers.

The X-Forwarded-For (XFF) header is a de-facto standard header for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or a load balancer. When traffic is intercepted between clients and servers, server access logs contain the IP address of the proxy or load balancer only. To see the original IP address of the client, the X-Forwarded-For request header is used.

The syntax is,

X-Forwarded-For: <client>, <proxy1>, <proxy2>
X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178

When a Http request flows through a proxy, the proxy appends its IP address to X-Forwarded-For header (if it respects this header).

Forwarded

However, since X- headers are not recommended anymore,

Custom proprietary headers can be added using the ‘X-‘ prefix, but this convention was deprecated in June 2012.

a standardized and enhanced header, Forwarded, is introduced.

# the original request is from 192.0.2.60, and passed through proxy 203.0.113.43
Forwarded: for=192.0.2.60; proto=http; by=203.0.113.43

# client can also append some obfuscated identifier like "secret" here, server can 
# then use it validate the integrity of a client.
Forwarded: for=23.45.67.89;secret=egah2CGj55fSJFs, for=10.1.2.3
X-Real-IP

Another somehow relevant header is X-Real-IP, which contains a single IP. You may find it, for example, somewhere in Nginx docs (ngx_http_proxy_module doc, ngx_http_realip_module doc).

不要在HTTP的GET请求里携带Request Body

2017 Nov 30

在设计RESTful service时,可不可以在一个GET请求中携带body? 答案是:最好不要这些做。

有一些RESTful service允许GET请求携带request body,比如Elasticsearch的search接口。 但这不是一种好的实现。 HTTP的规范在定义GET的语义时,规定server端应该只根据请求的URI来返回response。

[…] if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request. […] The GET method means retrieve whatever information ([…]) is identified by the Request-URI. […] A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

一个特定的http server,比如Elasticsearch,可以支持带body的GET。 但是也有很多http server会遵守规范,忽略GET的body,比如代理、cache server等。 假如在Elasticsearch前放置一个http cache server,比如Varnish,那么Varnish在丢弃GET的body后会返回一个错误的响应。

另外,一些http的客户端也可能不支持发送带body的GET请求,比如一些Javascprit的http client。 (虽然用X-HTTP-Method-Override header可以让http client以POST的方式发送GET请求来绕过这个限制, 但是如果请求流过某些代理,这些自定义的header可能会被丢弃。)

所以如果要在GET请求里携带数据,最好放在query string里,或者自定义的header(比如X-CSRF-TOKEN)、cookie里。

实际上,Elasticsearch也意识到这个问题,所以它支持通过query string来进行搜索。 (把整个body url encode之后放在source参数里,然后在source_content_type参数里指定source的内容格式是application/json。) Elasticsearch还保留着对带body的GET的支持,其中一个原因是大部分http client对URL的长度有限制。 如果你不像Elasticsearch这样需要在GET请求中发送大量数据,最好还是使用query string来发送数据。

Http Status Code 303

2017 Sep 12

303 See Other GET methods unchanged. Others changed to GET (body lost). Used to redirect after a PUT or a POST to prevent a refresh of the page that would re-trigger the operation.

假设之前请求的method不是GET,那么重定向302导致的请求可能会维持method不变。 (“GET methods unchanged. Others may or may not be changed to GET.”) 重定向303的不同之处是,它会把method改成GET

一个用例是,一般用户登录的请求是POST;登录失败时,需要重定向到之前的登录页面,访问这个登录页面应该要GET。 所以,重定向时要用303。

Session Management Cheat Sheet

2017 Mar 2

OWASP出品的关于session的非常详细的cheat sheet。 重点讲了如何安全地管理session。 session做为一种和用户名&密码等效的认证手段,session管理的安全性是很重要的。