Is $http_host dangerous?

No one has an answer to my question, so I figured out a solution:
http://forum.nginx.org/read.php?2,226823,226849#msg-226849

I had to replace $host with $http_host to get my problem
resolved…

But is this safe?

It seems like all $http_host is doing is to exposed the whole HOST
from header.
The explination http://forum.nginx.org/read.php?2,213799 here is still
not clear to me…

Someone has any idea why would $http_host be more dangerous?
Thanks.

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,226866,226866#msg-226866

On Sat, May 26, 2012 at 07:00:15PM -0400, jwxie wrote:

Hi there,

I had to replace $host with $http_host to get my problem
resolved…

But is this safe?

“safe” depends on what you do with the arbitrary content provided by
the user. If all you do is “send it straight back to them”, then it
probably is safe for you.

It seems like all $http_host is doing is to exposed the whole HOST
from header.

Yes: http://nginx.org/en/docs/http/ngx_http_core_module.html#variables

The explination http://forum.nginx.org/read.php?2,213799 here is still
not clear to me…

If I read that correctly, $http_host is “whatever the client sent in
the Host: header. This may be empty”.

$host is “the host part of the request, if any (typically none)”, or
else “the host part of the Host: header, converted to lowercase, if any
(typically something)”, or else “the first entry in the server_name
array of this server”.

Someone has any idea why would $http_host be more dangerous?

If you serve requests from a default server (so the Host: header isn’t
constrained by your server_name setting) and you use the $host or
$http_host variable as – for example – part of the filesystem path to
serve, then you may be surprised by their differences.

Both $http_host and $host are user-provided data. They are
sanitised differently. They are inherently safe. What you do with
them may be dangerous, or may just be inconvenient. What do you
see from

curl -i http://localhost:1111/forum

and

curl -i -H ‘Host:’ http://localhost:1111/forum

and

curl -i -H ‘Host: fake.example.comhttp://localhost:1111/forum

? Does any difference matter?

f

Francis D. [email protected]

Hi Francis,
Thanks for the response.

After reading the documentation,
http://wiki.nginx.org/HttpCoreModule#.24host

When the HOST is empty, it’s responded with 400 as expected.

I think the argument would come down to whether we trust the value sent
by the user.
In both use of $http_host and $host, I think the 3rd curl command is
trying to send a custom header whose HOST value is user-defined? I
believe that if we compromised the DNS or the network for example, there
is a possible way to hijack the nginx servers by modifying the
header…

Since $host is a strict version of $http_host, and when it’s empty it
uses $server_name directive, I believe it’s a small bit of extra
security layer… besides gettin rid off the port number in the
response?

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,226866,226882#msg-226882

On Sun, May 27, 2012 at 05:56:23PM -0400, x7311 wrote:

Hi there,

When the HOST is empty, it’s responded with 400 as expected.

Yes, that’s the expected response for HTTP/1.1.

But add a “-0” curl argument to make it use HTTP/1.0, and nginx should
allow the request through for your application to process.

I think the argument would come down to whether we trust the value sent
by the user.

The short answer is “never trust the value sent by the user” :wink:

I think it comes down to how you use the user-provided value, and what
you are protecting against.

In both use of $http_host and $host, I think the 3rd curl command is
trying to send a custom header whose HOST value is user-defined?

Yes. Strictly, every header has user-defined content, always. nginx
does do some validation on the content of Host: to catch some
obviously-malformed names, but it cannot catch all. $server_name is
fully under your control, so it may be appropriate to use that instead.

I
believe that if we compromised the DNS or the network for example, there
is a possible way to hijack the nginx servers by modifying the
header…

What do you mean by “hijack”?

And what problem are you trying to protect against?

If you echo back the Host: header you get in a Location: header, the
client may have difficulty following the redirection. That probably
isn’t for you to be worried about.

If you echo back the Host: header within html, then the client may treat
it as trusted-from-you, which would be bad. That probably is something
for you to avoid.

If you directly use the Host: header contents to determine which
internal resource to return, then you may end up revealing something
that you didn’t intend to. Or accessing an external server that you
didn’t intend to. That is certainly something for you to avoid.

Since $host is a strict version of $http_host, and when it’s empty it
uses $server_name directive, I believe it’s a small bit of extra
security layer… besides gettin rid off the port number in the
response?

Different variables, different uses. Possibly a completely different
variable would be useful, which could be “the host:port to include in
any redirection which the client can be expected to be able to use to
get to this server”. I’m not sure if that exists yet.

(I’m also not sure if it would be immediately useful outside of testing
or unusual port-forwarding scenarios that are already likely not working
elsewhere.)

f

Francis D. [email protected]

On Sun, May 27, 2012 at 06:16:06PM -0400, x7311 wrote:

Hi there,

Actually, I should reconsider my position on this after reading this:

http://stackoverflow.com/questions/1459739/php-serverhttp-host-vs-serverserver-name-am-i-understanding-the-ma

That page seems to be about variables made available by the PHP
implementation in apache.

In nginx, PHP is (typically) accessed using fastcgi, so the $_SERVER
variables are exactly what is set in (again, typically) fastcgi.conf.

HTTP_HOST is “the Host: header, if any”. SERVER_NAME from nginx is “the
first element of server_name”, but from apache appeared to depend on the
Host: header.

For both apache and nginx, HTTP_* come straight from the user, and some
other variables come from the server admin.

I am not sure how nginx reacts to that, but according to you Francis,
you seems to be inline with Chris Shiflett that neither is safe nor
insecure. They are pretty much the same thing.

Agreed. Once you know what the variables represent, you can decide what
is the appropriate one for your use case.

It is not difficult to construct a scenario in nginx where $server_name
is “one”, $http_host is “two”, and $host is “three”. But that’s unlikely
to be done by an innocent user.

Under one circumstances, can you think of a way to exploit when using
$http_host?

Using $http_host instead of $host?

Pick any circumstance where they are different, and the difference
matters. A simple one is “root /var/www/$http_host”. Now “curl
http://public/” and “curl http://PUBLIC/” will probably return different
content, where “root /var/www/$host” would have returned the same.

Or

echo 'GET http://public/ HTTP/1.0
Host: private

’ | nc public 80

would also probably return different content (and that one might also
“work” for “proxy_set_header Host $http_host” to an upstream server).

It depends on how the variables are used. And it can probably all be
avoided by appropriate configuration elsewhere.

f

Francis D. [email protected]

Actually, I should reconsider my position on this after reading this:
http://stackoverflow.com/questions/1459739/php-serverhttp-host-vs-serverserver-name-am-i-understanding-the-ma

I am not sure how nginx reacts to that, but according to you Francis,
you seems to be inline with Chris Shiflett that neither is safe nor
insecure. They are pretty much the same thing.

Under one circumstances, can you think of a way to exploit when using
$http_host?

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,226866,226883#msg-226883