Forum Discussion
Prevent X-Forwarded-For spoofing
We insert an X-Forwarded-For header to pass back to our web servers. One application we have looks to this header to allow or deny certain servers access to us. However, we want to prevent spoofing the header for obvious reasons. The hope is that the LTM can peel off any outside X-Fordwarded-For headers and replace them with its own X-Fordwarded-For that has the IP of the actual client that is connecting. We are running 11.4.1 which has an "Accept XFF" option, but this is disabled. Reading the docs makes it sound like having that option disabled will give us what we need, but it does not work. I also tried adding X-Forwarded-For to the "Request Header Erase" option and it removes all X-Forwarded-For headers even the ones the LTM creates.
I can spoof X-Fordwarded-Fors no sweat still. Any bright ideas on how to peel off outside X-Forwarded-Fors?
23 Replies
- Kevin_Stewart
Employee
The XFF option in the HTTP profile is an insert, so yes it will allow spoofing. What you need is a replace function:
when HTTP_REQUEST { foreach x [HTTP::header names] { if { $x equals "X-FORWARDED-FOR" } { HTTP::header remove X-FORWARDED-FOR HTTP::header replace X-FORWARDED-FOR [IP::client_addr] } } } - Bubbagump_12531
Nimbostratus
Hrm, so I copied this into an iRule verbatim and applied it to my Virtual Server as the first rule in line. I then removed the X-Forwarded-For option form my http profile and still the same behavior. What am I missing? Thanks for your help!
- Kevin_Stewart
Employee
Is it that you're injecting additional (spoofed) X-FORWARDED-FOR headers in the client request and still see these arriving at the server?
- Bubbagump_12531
Nimbostratus
Yes, that is exactly right. I am using a spoofing plugin via Firefox to insert a spoofed X-Forwarded-For header. Then, in sniffing the traffic coming from the F5, the spoofed headers are still there and Apache is happy to log them. So my machine at 192.168.x.x shows up via X-Forwarded-For as my spoofed IP 1.2.3.4
- What_Lies_Bene1
Cirrostratus
Perhaps line 5 should be 'insert'?
- Kevin_Stewart
Employee
Could it be a case thing?
when HTTP_REQUEST { foreach x [HTTP::header names] { if { [string tolower $x] equals "x-forwarded-for" } { HTTP::header remove $x HTTP::header replace X-FORWARDED-FOR [IP::client_addr] } } } - Bubbagump_12531
Nimbostratus
So it is indeed a case thing as changing it to camel case identically as I had it in the plugin worked. How do we deal with the 1001 different forms of case? X-Forwarded-For, X-FORWARDED-FOR, x-forwarded-for, X-forwarded-for, x-Forwarded-for, x-Forwarded-for etc etc. Is there an equivalent to 'grep -i'?
- Kevin_Stewart
Employee
The last version of the iRule above evaluates against the forced lowercase version of the header name. Is that version working for you?
- Bubbagump_12531
Nimbostratus
Bah, I completely missed that. Yes it does work. Thanks so much. In the mean time I was mucking around with -nocase, but that is certainly a much more elegant solution.
However, is this not inefficient? It appears to remove the headers inserted by the HTTP profile too and not just outside headers. So perhaps an if exists, replace, else, insert and completely forgo the insert via the HTTP policy? Would this work? (or some permutation as I am by no means a TCL guy)
when HTTP_REQUEST { foreach x [HTTP::header names] { if { [string tolower $x] equals "x-forwarded-for" exists} then if { [string tolower $x] equals "x-forwarded-for" } { HTTP::header remove $x HTTP::header replace X-FORWARDED-FOR [IP::client_addr] } else {HTTP::header insert X-FORWARDED-FOR [IP::client_addr]} }}
- Kevin_Stewart
Employee
The [HTTP::header names] command produces a list that you're going to iterate through. The HTTP::header remove $x command inside that loop only removes the offending header and inserts/replaces with a new one of your choosing. Any other headers will remain untouched.
- Bubbagump_12531
Nimbostratus
Right, but won't the HTTP policy then also put on an addition X-Forwarded-For header? My thought is an iRule to do it all.
Basic logic now:
If a header exists coming in, remove and create your own.
THEN
HTTP policy adds another header.
I am thinking a single rule that works like:
If a header exists coming in, remove and create your own. Else if no header, create your own.
THEN
HTTP policy does nothing regarding XFF headers.
- Kevin_Stewart
Employee
Right, but won't the HTTP policy then also put on an addition X-Forwarded-For header? My thought is an iRule to do it all.
You must remove the XFF option from the HTTP profile.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
