Non-standard HTTP headers 'X-Forwarded-Host' etc appear in the HTTP response

11k views Asked by At

We have an application deployed on the AWS. In front, an AWS load balancer accepts all of incoming HTTP requests; EC2 instances are directly behind this balancer. On individual instance, a HAproxy receives all requests and delegates then to the real application server based on Java(In our special case, haproxy and business application server are on the same EC2 instance, the haproxy doesn't play load balance roles just for relaying http requests, in other words, haproxy and application server are one-to-one mapping).

When we tried to fire up a http call to this system:

Request

GET /token HTTP/1.1
Host: xxx.xxx.xxx.xxx

Response

HTTP/1.1 403 Forbidden 
X-Forwarded-Proto: https 
X-Forwarded-For: xxx.xxx.xxx.xxx 
X-Forwarded-Port: 443 
X-Forwarded-Host: xx.xx.xx.xxx 
Date: Wed, 09 Dec 2015 22:04:06 GMT 
Server: WSO2-PassThrough-HTTP 

In my understanding, X-Forwarded-* should only appear on the server side in order for servers to identify where incoming requests are from when there are proxies in-between. I don't know why those headers appear in the response as well. It made me have concerns on leaking the internal IPs to potential malicious clients.

The following is code snippets for haproxy settings:

frontend worker
bind :443 ssl crt xxx crt xxx crt xx accept-proxy no-sslv3 no-tls-tickets
mode http
acl forwarded hdr_cnt(X-Forwarded-Host) gt 0
acl trusted src 127.0.0.0/24
capture request header X-Forwarded-For len 64
default_backend worker
http-request deny if METH_TRACE
http-request set-header X-Forwarded-Host %[dst] unless forwarded trusted
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
option forwardfor if-none
reqidel ^X-Forwarded-For:.* unless trusted
rspadd Strict-Transport-Security:\ max-age=63072000;\ includeSubdomains;\ preload
use_backend xxx.xxx.xxx if { ssl_fc_sni -i xxx.xxx.xxx }
use_backend xxx.xxx.xxx if { ssl_fc_sni -i xxx.xxx.xxx }

Please advise why those non-standard headers appear in the http responses and if this is risky for the security.

1

There are 1 answers

3
Castaglia On BEST ANSWER

AWS ELBs automatically add the X-Forwarded-For, X-Forwarded-Port, and X-Forwarded-Proto request headers, per the AWS ELB docs; they do not use the X-Forwarded-Host header. Thus this rule in your haproxy config is a little suspect:

acl forwarded hdr_cnt(X-Forwarded-Host) gt 0

Instead, you might try:

acl forwarded hdr_cnt(X-Forwarded-For) gt 0

The X-Forwarded-Host request header is more unusual; unless your backend server (WS02, from the looks of it) needs that header, you might remove that, and other X-Forwarded-* rules from your haproxy config altogether, since those values should be coming from the AWS ELB. That is, you might remove these altogether:

http-request set-header X-Forwarded-Host %[dst] unless forwarded trusted
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }

As for whether it's a security concern -- only for HTTP requests, not HTTPS requests. And that's only because, without SSL, it's possible for someone to possibly intercept and eavesdrop on those response headers. Such an attacker would already know the client's IP address (and thus the value for X-Forwarded-For), would know the TCP destination port (and thus the value for X-Forwarded-Port), and would know that it's not SSL (and thus would know X-Forwarded-Proto: http). Ideally, though, as you point out, these headers would not appear in the response at all. (It's unusual for HTTP servers to echo X-Forwarded-* request headers like these in their response; I was thus trying to read the WS02 docs to see if it could be configured to do something like that.)

Thus while you research this, you could have haproxy remove these response headers, using something like:

rspdel ^X-Forwarded-.*:.*

Hope this helps!