I've encountered some issues with spoofing of the Host value in HTTP transactions. In order to close security holes related to these types of attacks, I need to securely detect what the domain of the running ASP.NET site. Unfortunately, all of the references I find suggest you use Request.ServerVariables["HTTP_HOST"]
or Request.Url.Host
. By submitting invalid HTTP packets, I have been able to set invalid host values and observer the behavior they're causing with both function calls. The behavior I'm seeing is different depending on the type of .NET environment I use.
In IIS 6, the injected value always shows up, no matter if I access the request directly in an MVC Controller action, or in a location that requires me to access the values through HttpContext.Current.Request
.
In the Visual Studio 2012 ASP.Net Development Server, I only see the injected values in library code we deployed to the project through a NuGet package. In the NuGet package I have to use the HttpContext.Current
since the code runs outside of the scope of the web application. When I stay within the scope of the web application's namespace, even if I have to call the HttpContext.Current
, it will provide the correct unspoofed value.
For all of this testing, I have been using ASP.NET 4.0. Has this behavior changed in ASP.NET 4.5 and IIS 8? Is there a way to securely get the domain name? It is also possible to do the same attack against PHP , but Apache has a way that can prevent these types of attacks . Does IIS?
Example of the code I've been having problems with:
string siteName1 = HttpContext.Current.Request.ServerVariables["HTTP_HOST"];
string siteName2 = HttpContext.Current.Request.Url.Host;
Example of an invalid HTTP Packet:
GET: https://sampledomain.com/Items/Index
Host: fakedomain
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0
I've done my testing with the Firefox extension Live HTTP headers which has allowed me to quickly record and replay my requests to the web server.
In IIS you could setup the site's bindings so that it only gets requests matching particular host header value(s).
That way if someone tries to spoof the host header value, your website won't even see the request.
Not exactly an answer to your question, but possibly an solution to your problem.
It's unclear what you mean by "securely", but the entire point of the Host header is to allow the browser to specify the host it intended to talk to.
RFC 2616 has a few things to say about the Request-URI
and Host
header:
To allow for transition to
absoluteURI
s in all requests in future versions of HTTP, all HTTP/1.1 servers MUST accept theabsoluteURI
form in requests, even though HTTP/1.1 clients will only generate them in requests to proxies....
The most common form of
Request-URI
is that used to identify a resource on an origin server or gateway. In this case the absolute path of the URI MUST be transmitted (see section 3.2.1,abs_path
) as theRequest-URI
, and the network location of the URI (authority) MUST be transmitted in aHost
header field....
- If
Request-URI
is anabsoluteURI
, the host is part of theRequest-URI
. AnyHost
header field value in the request MUST be ignored....
The
Host
field value MUST represent the naming authority of the origin server or gateway given by the original URL. This allows the origin server or gateway to differentiate between internally-ambiguous URLs, such as the root "/" URL of a server for multiple host names on a single IP address....
A client MUST include a
Host
header field in all HTTP/1.1 request messages. If the requested URI does not include an Internet host name for the service being requested, then theHost
header field MUST be given with an empty value....
The requirements that clients and servers support the
Host
request- header, report an error if theHost
request-header (section 14.23) is missing from an HTTP/1.1 request, and accept absolute URIs (section 5.1.2) are among the most important changes defined by this specification....
- Both clients and servers MUST support the
Host
request-header.- A client that sends an HTTP/1.1 request MUST send a
Host
header.- Servers MUST report a 400 (Bad Request) error if an HTTP/1.1 request does not include a
Host
request-header.- Servers MUST accept absolute URIs.
In summary, while a conforming HTTP client cannot send the request
GET https://example.com/ HTTP/1.1
Host: fakedomain.invalid
to an origin server, an HTTP/1.1 server is required to accept it, use example.com
as the host, and "ignore" the Host
header. Request.Url.Host
should definitely be example.com
; if not it's a bug in IIS. I'm less certain about Request.ServerVariables["HTTP_HOST"]
, but a reasonable interpretation of "ignoring" the host header would be to rewrite it to say example.com
.
(Incidentally, the two other servers I've just tested don't follow the spec either: Apache 2.4.3 assumes that a request to an absoluteURI
must be one to a proxy and denies it on that basis, while lighttpd 1.4.28 allows GET http://example.com/ HTTP/1.1
without a Host
header.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.