Forum Discussion
Host Header Validation
- Jul 28, 2016
A data-group is a convenience rather than a necessity.
I tried the following on 11.5.4:
when HTTP_REQUEST { if { [HTTP::host] ne "xyz.com" } { reject } }
I tried all of the following combinations:
- HTTP/1.1 Host header xyz.com;
- HTTP/1.1 Host header foo.com;
- HTTP/1.0 no Host header;
- HTTP/1.1 Host header xyz.com followed by HTTP/1.0 no Host header;
- HTTP/1.1 Host header xyz.com followed by HTTP/1.1 Host header foo.com
Case 1: allowed;
Case 2: rejected (i.e., TCP RST);
Case 3: rejected;
Case 4: allowed then rejected;
Case 5: allowed then rejected.
Incidentally, if a pool is assigned to the VS, then the else clause isn't needed (it's the default anyway).
Having said all of that, your issue may be relate to this note, found in the reject explanation:
Subsequent code in the current event in the current iRule or other iRules on the VS are still executed prior to the reset being sent.
I recommend putting a return after the reject.
A data-group is a convenience rather than a necessity.
I tried the following on 11.5.4:
when HTTP_REQUEST {
if { [HTTP::host] ne "xyz.com" } {
reject
}
}
I tried all of the following combinations:
- HTTP/1.1 Host header xyz.com;
- HTTP/1.1 Host header foo.com;
- HTTP/1.0 no Host header;
- HTTP/1.1 Host header xyz.com followed by HTTP/1.0 no Host header;
- HTTP/1.1 Host header xyz.com followed by HTTP/1.1 Host header foo.com
Case 1: allowed;
Case 2: rejected (i.e., TCP RST);
Case 3: rejected;
Case 4: allowed then rejected;
Case 5: allowed then rejected.
Incidentally, if a pool is assigned to the VS, then the else clause isn't needed (it's the default anyway).
Having said all of that, your issue may be relate to this note, found in the reject explanation:
Subsequent code in the current event in the current
iRule or other iRules on the VS are still executed
prior to the reset being sent.
I recommend putting a return after the reject.
- Chronos_258816Jul 28, 2016Nimbostratus
Good to know that it should be working as intended as per your examples above. I have placed the return after the reject and hope that takes care of the issue. If not, I need to see just how the exploits are being done.
- ekaleidoJul 28, 2016Cirrus
Curious because I'm not near a VE to test on, but is the following case sensitive:
[HTTP::host] ne "xyz.com"
As in, could Xyz.com create a different behavior?
- VernonWellsJul 29, 2016Employee
Naturally, but actually, that snippet is "more secure", in the sense that it is stricter. That is, if the Host header is Xyz.com (which, by RFC, means exactly the same thing as xyz.com), then it will be rejected. To allow any case (which, again, would be the RFC conforming choice):
if { [string tolower [HTTP::host]] ne "xyz.com" } { reject }
- Chronos_258816Jul 29, 2016Nimbostratus
Adding the "return" did fix my issue, Very much appreciated for the assistance! Now to figure out how to get it to also validate when the host header is an IP address, as my attempts aren't working their either.
- VernonWellsJul 29, 2016Employee
The Host header can include a port suffix, which often trips things up. You may wish to try something like this:
tmsh create ltm data-group internal dg-allowed-hosts \ type string records add { xyz.com { data "allow" } 10.11.12.13 { data "allow" } }
This is the Data Group mechanism mentioned before. To reference the Data Group in the iRule, use the
method. So, for the iRule:class
when HTTP_REQUEST { if { [class lookup [getfield [string tolower [HTTP::host]] : 1] dg-allowed-hosts] eq "" } { reject return } }
You may add as many records as you require in the data-group definition. If you want to match on netblocks as well, things become slightly more complex (you need two data-groups: one for string hostnames and one for IPs/netblocks).
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