Classic ASP: ServerVariables["HTTP_HOST"] forging - security

According to this MSDN article https://msdn.microsoft.com/en-us/library/ms525396(v=vs.90).aspx these variables are set based on headers. I'm curious if the HTTP_HOST variable is spoofable. I've run a few tests that indicate it's not spoofable, but I'd like to be sure.
EDIT: For clarity, I'm curious if something like a server proxy, man in the middle, or just someone who knows how to use netcat could forge the appropriate headers in order to manipulate HTTP_HOST within my scripts.

Yes it is spoofable.
A malicious user for your website can set any host header they want in their HTTP request and the HTTP_HOST variable will reflect that:
GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
The only caveat is that it must be bound on your webserver. For example, if you use an IIS webserver you specify which hosts your website is bound to. This can be blank for "any" or you can set it to a specific domain name. If the latter, then at attacker sending
GET / HTTP/1.1
Host: www.foo.com
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
to your example.com domain would not hit your example.com website but would hit the default IIS website if that itself was running and if this has a blank binding. If it wasn't running then an error is returned instead. These measures will protect you from spoofing in attacks such as cache poisoning or spoofing malicious password reset emails.
Also note that HTTPS sites do not use the host header. They either bind directly to a single IP, or they use Server Name Indication (SNI), which is sent as part of the TLS/SSL handshake to determine which website the request is made to. IIS 8 and above support SNI and this introduces a per binding certificate that is interpreted in the same way as the host header for plain HTTP. Note that this can be spoofed in the same way by an attacker at the browser end because they can send whichever domain name they want.
However, SNI information cannot be altered by a Man-In-The-Middle attacker like it can with a plain HTTP request. This is because the browser will check that the domain name matches the requested site and will warn the user if this is not the case. There is no such authentication with plain HTTP. The only attack I could think of in a MITM scenario with HTTPS is one where wildcard certificates are used and that a MITM could make the user hit a different site than expecting with no browser warning. However the TLS handshake FINISHED message hash would not calculate if this had been altered by a MITM, so that should mitigate this attack.

Related

Could automatically redirecting all HTTP traffic to HTTPS inadvertently encourage a man-in-the-middle attack vector?

If your web server implements HTTPs, it's common practice to 301 redirect all http://* URLs to their https:// equivalents.
However, it occurs to me that this means that the client's original HTTP request (and any data contained in it) remains fully unencrypted, and only the response is encrypted. Does automatically "upgrading" all insecure requests on the server end effectively encourage clients to continue sending data to insecure HTTP endpoints, more or less downgrade attacking myself?
I realize I can't stop a client from insecurely sending any data to any endpoint, but does the practice of automatically redirecting HTTP to HTTPS "condone" the client doing so? Would it be better practice to instead outright reject all HTTP traffic that could contain sensitive data and make it the browser's responsibility to attempt or recommend the upgrade to HTTPS?
This is indeed a known issue, and HTTP Strict Transport Security (HSTS)—released in 2012—aims to solve it. It is an HTTP header field which takes the form:
Strict-Transport-Security: max-age=<seconds> [; includeSubDomains]
HSTS informs the browser via that all connections to a given domain must be "upgraded" to https, even if they were specified as non-secure http`:
The UA MUST replace the URI scheme with "https"
This applies to all future connections to the domain (including following links), for the duration of the max-age specified in the header.
However this does leave open a potential vulnerability on the user's first visit to a domain with HSTS (if the header were stripped by an attacker). Google Chrome, Mozilla Firefox, Internet Explorer and Microsoft Edge attempt to limit this problem by including a "pre-loaded" list of HSTS sites.
So this preloaded list has all popular websites, All you may see in this chromium link, this list is humongous(10M), thereby solving aforementioned problem to a certain extent.

Use Reverse Proxy rewrite rule to fetch content from site accessible through HTTP proxy

A client of mine is trying to use an IIS Application Request Routing rule to reverse proxy the contents of another site (controlled by the same client). So far, no issues.
But, from the IIS server the other site is only available through a standard HTTP proxy. It looks like ARR totally ignores the System and .NET Proxy settings.
We tried setting the default proxy in the web.config, that is ignored.
We tried setting the system proxy through netsh winhttp set proxy.
We changed the settings in the Internet Explorer connection settings.
All to no avail.
I can't find any documentation on whether ARR supports reverse proxy rules through another proxy. I can imagine this is not supported.
An HTTP request over an HTTP proxy is actually making the same request to the proxy using the absolute url instead of relative in after the method name.
GET / HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
would be
GET http://example.com/ HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Of course the request needs to be made to the proxy server.
You could try achieving this changing rewrite rule. I can't provide an example since I don't have access to a Windows server but you can try to get some guidance here.

Why does RFC 6797 forbid sending of the Strict-Transport-Security header over plain HTTP responses?

When reading the spec for HSTS (Strict-Transport-Security), I see an injunction in section 7.2 against sending the header when accessed over http instead of https:
An HSTS Host MUST NOT include the STS header field in HTTP responses
conveyed over non-secure transport.
Why is this? What are the risks if this is violated?
The danger is to the availability of the website itself. If the website is able to respond (either now or in the future) over HTTP but not over HTTPS, it will semi-permanently prevent browsers from accessing the site:
Browser: "I want http://example.com"
ExampleCom: "You should go to the https:// URL now and for the next 3 months!"
Browser: "I want https://example.com"
ExampleCom: [nothing]
By only serving the STS header over HTTPS connections, the site guarantees that at least right now it is not pointing browsers to an inaccessible site. Of course, if the max-age is set to 3 months and the HTTPS site breaks tomorrow, the effect is the same. This is merely an incremental protection.
If your server cannot positively tell from request characteristics whether it is being accessed over HTTP vs. HTTPS, but you believe you have set up your website to only be accessible over HTTPS anyhow (e.g. due to SSL/TLS termination in an nginx proxy), it should be safe to serve the header all the time. But if you want to serve both, e.g. if you wish to serve HTTP->HTTPS redirects from your server, find out how your proxy tells you about the connection and start gating the STS header response on that.
(Thanks to Deirdre Connolly for this explanation!)
Not sure if you have a specific issue you are trying to solve, or are only asking for curiosity sake but this might be better asked on http://security.stackexchange.com
Like you I can't see the threat from the server sending this over HTTP. It doesn't really make sense, but I'm not sure if there is a risk to be honest. Except to say if you can't set up the header properly then perhaps you're not ready to implement HSTS as it can be dangerous if misconfigured!
The far bigger danger is if a browser was to process a HSTS header received over HTTP, which section 8.1 explicitly states it MUST ignore:
If an HTTP response is received over insecure transport, the UA MUST
ignore any present STS header field(s).
The risk here is that a malicious attacker (or an accidentally misconfigured header) could take a HTTP-only website offline (or the HTTP-only parts of a mixed site) if a browser incorrectly processed it. This would effectively cause a DoS for that user(s) until either the header expiries or the site implements HTTPS.
Additionally if a browser did accept this header over HTTP rather than HTTPS, it could be possible for a MITM attacker to expire the header by setting it to a max-age of 0. For example if you have a long HSTS header set on https://www.example.com but attacker was able to publish a max-age=0 header with includeSubDomain over http://example.com, and the browser incorrectly processed that, then it could effectively remove the protection HTTPS gives to your www site.
For these reasons it's very important that clients (i.e. webbrowsers) implement this correctly and ignore the HSTS header if served over HTTP and only process it over HTTPS. This could be another reason the RFC states servers must not send this over HTTP - just in case a browser implements this wrong but, to be honest, if that happens then that browser is putting all HTTP only websites at risk as a MITM attacker could add it as per above.

What's the point of the X-Frame-Options header?

I work on an application where users can embed their website within surrounding content by loading it in an iframe. This obviously relies on the X-Frame-Options not being set on the users website to work. I was asked by a client to create a reverse proxy because they didn't want to remove the X-Frame-Options header from their site for security concerns.
I setup the proxy and everything works but what's the point of the X-Frame-Options header if its as simple as creating a proxy to circumvent?
I understand the header exists to prevent clickjacking but if anyone can just make a proxy to workaround it... does it really increase security?
I don't come from the enterprise dev world, can you help me understand the reasoning behind why the IT department would be resistant to removing the header?
I noticed google.com and facebook.com also set the header, so it can't be completely pointless can it?
Thanks
Any site served over http can have its content altered by using a proxy for example. So yes this is fairly pointless on http sites since it's so easily defeated.
Serving a site over https prevents this unless you have a proxy server which also intercepts https traffic. This is only possible by the proxy acting as a man-in-the-middle (MITM) so it decrypts the traffic at the proxy and then re-encrypts the traffic to send on to the server and same in way back. For this to work the proxy server either needs to know the server private key or, more likely, replaces the cert presented to its client with its own copy.
While MITM is usually associated with attacks there are some legitimate scenarios (though many argue even these are not legitimate and https should be secure!):
Anti-virus software can do this to scan requests to protect your computer. If you run Avast for example and have SSL scanning turned on (think it's on by default) and go to https://www.google.com and look at the cert you will notice it's been issued by Avast instead of by Google as usual. To do this requires the antivirus software to have installed an issuer certificate on your PC from which it can issue these replacement certs which your browser will still accept as real certs. Installing this issuer cert requires Admin access which you temporarily give when installing the anti-virus software.
Corporate proxies do a similar process to allow them to monitor https traffic from its employees. Again it requires an issuer installed on the PC using admin rights.
So basically it's only possible to use a proxy like you suggest for https traffic if you already have, or have had in the past, Admin rights in the PC - at which case all bets are off anyway.
The only other way to do this is to keep traffic on http using a proxy. For example if you request www.google.com then this normally redirects to https://www.google.com but your proxy can intercept that redirect request and instead keep the client->proxy connection on https, allowing the proxy to amend the request to strip out headers. This depends on the users not typing https, not noticing there is no green padlock and can be defeated with technologies like HSTS (which is automatically preloaded in some browsers for some sites like google.com). So not really reliable way to intercept traffic.
Many secure sites use X-Frame-Options to prevent clickjacking
Clickjacking
Clickjacking Defense Cheat Sheet
This prevents attackers from tricking users through transparent layers from performing actions they are unaware of on sites they didn't even know they loaded. Furthermore, this attack only works with frames that are directly served from the attacked/victim site's domain in the user's browser.
You may think that you can just reverse proxy the site and remove the frame busting header. But your proxy is not receiving or sending the end users cookies to the victim site. These secure sites rely on an active session, and as such will interpret the request from the proxy as coming from an unauthenticated user completely defeating the point of clickjacking.

Does https encrypt the whole URL?

I googled a lot and many answers are Yes. For example: Is GET data also encrypted in HTTPS? But the senior security engineer in our company told me the URL would not be encrypted.
Image that, if the URL was encrypted, how does the DNS server find the host and connect?
I think is this is very strong point although it's against most of the answers. So I'm really confused and my questions are:
Does https encrypt the everything in the request? (including the URL, host, path, parameters, headers)
If yes, how the DNS server decrypt the request and send it to the host server?
I tried to access https://www.amazon.com/gp/css/homepage.html/ref=ya_surl_youracct and my IE sent two requests to the server:
First:
CONNECT www.amazon.com:443 HTTP/1.0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: www.amazon.com
Content-Length: 0
DNT: 1
Connection: Keep-Alive
Pragma: no-cache
Second:
GET /gp/css/homepage.html/ref=ya_surl_youracct HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US,zh-CN;q=0.5
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: www.amazon.com
DNT: 1
Connection: Keep-Alive
It seems my browser has requested twice: the first time is to establish the connection with host (without encryption) and the second time send an encrypted request over https? Am I right? If I am understanding this correctly, when a client call the RESTFUL API using https, it sends the requests (connection and get/post) twice every time?
The URL IS encrypted from the time it leaves the browser until it hits the destination server.
What happens is that the browser extracts the domain name and the port from the URL and uses that to resolve DNS itself. Then it starts an encrypted channel to the destination server IP:port. Then it sends a HTTP request through that encrypted channel.
The important part is anyone but you and the destination server can only see that you're connecting to a specific IP address and port. They can't tell anything else (like specific URLs, GET parameters, etc).
Attackers can't even see the domain in most cases (though they can infer it if there is actually a DNS lookup - if it wasn't cached).
The big thing to understand is that DNS (Domain Name Service) is a completely different service with a different protocol from HTTP. The browser makes DNS lookup requests to convert a domain name into an IP address. Then it uses that IP address to issue a HTTP request.
But at no time does the DNS server receive a HTTP request, and at no time does it actually do anything other than provide a domain-name - IP mapping for users.
While the other responses are correct so far as they go, there are many other considerations than just the encryption between the browser and the server. Here are some things to think about...
The IP address of the server is resolved.
The browser makes a TCP socket connection to the server's IP address using TLS. This is the CONNECT you see in your example.
The request is sent to the server over the encrypted session.
If this was all there is to it, you are done. No problem.
But wait, there's more!
Having the fields in a GET instead of a POST reveals sensitive data when...
Someone looks in the server logs. This might be a snoopy employee, but it can also be the NSA or other three-letter government agency, or the logs might become public record if subpoenaed in a trial.
An attacker causes the web site encryption to fall back to cleartext or a broken cipher. Have a look at the SSL checker from Qualsys labs to see if a site is vulnerable to this.
Any link on the page to an external site will show the URI of the page as the referrer. User ID and passwords are unintentionally yet commonly given away in this fashion to advertising networks. I sometimes spot these in my own blog.
The URL is available in the browser history and therefore accessible to scripts. If the computer is public (someone checks your web site from the guest PC in the hotel or airport lounge) the GET request leaks data to anyone else using that device.
As I mentioned, I sometimes find IDs, passwords and other sensitive info in the referrer logs of my blogs. In my case, I contact the owner of the referring site and tell them they are exposing their users to hacking. A less scrupulous person would add comments or updates to the site with links to their own web site, with the intention of harvesting the sensitive data in their referrer logs.
So your company's senior security engineer is correct that the URL is not encrypted in many places where it is extremely important to do so. You and the other respondents are also correct that it is encrypted in the very narrow use case of the browser talking to the server in context of a TLS session. Perhaps the confusion you mention has to do with the difference in the scope of these two use cases.
Please see also:
Testing for Exposed Session Variables (OTG-SESS-004)
Session Management - How to protect yourself (Note that "always use POST" is repeated over and over on this page.)
Client account hijacking through abusing session fixation on the provider
The URL (also known as "Uniform Resource Locator") contains four parts:
Protocol (e.g. https)
Host name (e.g. stackoverflow.com)
Port (not always included, typically 80 for http and 443 for https)
Path and file name or query
Some examples:
ftp://www.ftp.org/docs/test.txt
mailto:user#test101.com
news:soc.culture.Singapore
telnet://www.test101.com/
The URL as an entire unit is not actually encrypted because it is not passed in its entirety. The URL is actually pulled apart into bits and each part is used in different ways. E.g. the protocol portion will tell your browser how to use the rest of the URL, the host name will tell it how to look up the IP address of the intended recipient, and the port will tell it, well, which port to use. The only portion of the URL that is passed in the payload itself is the path and query, and that portion is encrypted.
If you take a look at an HTTP request in the raw, it looks something like this:
GET /docs/index.html HTTP/1.1
Host: www.test101.com
Accept: image/gif, image/jpeg, */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
(blank line)
--Body goes here--
What you see in the example above is passed. Notice the full URL appears nowhere. The host header can actually be omitted completely (it is not used for routing). The only portion of the URL that appears here is to the right of the GET verb, and only includes the rightmost portion of the original URL. The protocol and the port number appear nowhere in the message itself.
Short answer: Everything to the right of the port number in the URL is included in the payload of the https request and is in fact encrypted.

Resources