简体   繁体   中英

How do I securely get the domain name of the running ASP.NET site

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 the absoluteURI 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 the Request-URI , and the network location of the URI (authority) MUST be transmitted in a Host header field.

...

  1. If Request-URI is an absoluteURI , the host is part of the Request-URI . Any Host 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 the Host header field MUST be given with an empty value.

...

The requirements that clients and servers support the Host request- header, report an error if the Host 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM