IETF RFC 2616 Section 4.2 allows a request to contain multiple headers with the same field-name as long as chronological order of insertion is preserved and their values can be converted into single header with a comma-separated list of values.


message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded. F5 will not overwrite any existing X-Forwarded-For. Nor will it concatenate existing X-Forwarded-For into a single comma-separated value. Instead, it will insert an additional X-Forwarded-For at the tail end of the collection.

But what about an environment with multiple clients, proxies, CDNs, traffic-managers, servers that engage in manipulation of the X-Forwarded-For collection ?

There would seem to be an advantage to enforcing a uniform practice. But what is the best practice ?

F5 BIG-IP default http profile insert header accumulates an additional X-Forwarded-For at the end of a request's pre-existing collection of XFF headers, preserving order.

AWS ELB encourages consolidation of an incoming request's multiple X-Forwarded-For into a single header containing a comma-delimited list of XFF IPs, plus the user host address, preserving order.

Other devices may employ other variations.

Does there exist an agreed-upon recommendation or de facto standard for heterogeneous environments ?

Further, is any timestamp data provided that would allow code to definitively sort X-Forwarded-For headers in chronological order of addition for the case where previous manipulations of XFF headers are suspect.


Yes, there's a standard: Don't use X-Forwarded-For at all.

RFC 7239 defines the Forwarded header, which has rather different semantics from X-Forwarded-For, and new implementations ought to be using it. Unfortunately it suffers from the same problem you have identified with X-Forwarded-For here: it may be defined twice in a request or contain a comma separated list of values. Proxies are also allowed to delete it entirely.

And yes, there's a best practice: Use a different header name internally.

Remember that X-Forwarded-For and its replacement Forwarded contain untrusted input. It is trivial for a client to put whatever they want in such a header. If you really need to know the public IP address of whatever connected to your server, stick it in a different header. For instance, CloudFlare uses CF-Connecting-IP for this purpose. I've also seen Client-IP and X-Real-IP used in nginx (where you can define anything you want). Whatever name is used, your load balancers should be sending the requester's IP address in some header other than X-Forwarded-For or Forwarded.

  • Thanks Michael, very informative. However, our network traffic will need to continue to rely on XFF for quite some time. We have dozens of legacy client apps, proxies, traffic-managers, app-specific routers, server sites & services, many of which inject XFF or rely on presence of XFF. I'm trying to determine if should add code within gateway traffic-managers to consolidate multiple XFF into a single header with comma-separated list of values, or continue to allow accumulation of XFF collection on the request. – BaltoStar Jul 11 '15 at 19:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.