# Is $http\_host dangerous?

**URL:** <https://www.ruby-forum.com/t/is-http-host-dangerous/220070>\
**Category:** NGINX\
**Created:** [May 27, 2012, 1:00am UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070 "2012-05-27T01:00:56Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gurdipe\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Gurdipe\_D](https://www.ruby-forum.com/u/Gurdipe_D)\
**Post date:** [May 27, 2012, 1:00am UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070/1 "2012-05-27T01:00:56Z")

</div>

No one has an answer to my question, so I figured out a solution:

> **[Re: ssh-tunnel into website nginx strips out port number in response](https://forum.nginx.org/read.php?2,226823,226849#msg-226849)**
>
> Same post is made here: http://serverfault.com/questions/392530/nginx-when-tunnel-the-url-redirects-without-port-number But I will make a shorter version (as much as possible) I want to be able to ssh-tunnel into my Django website, so I can work...

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 [The real difference between $host and $http\_host](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:

> **[Is $http\_host dangerous?](https://forum.nginx.org/read.php?2,226866,226866#msg-226866)**
>
> 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\`

---

<div class="post-metadata">

**Author:** ![jwxie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@jwxie](https://www.ruby-forum.com/u/jwxie)\
**Post date:** [May 27, 2012, 1:23pm UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070/2 "2012-05-27T13:23:44Z")

</div>

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: [Module ngx\_http\_core\_module](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables)

> The explination [http://forum.nginx.org/read.php?2,213799](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](http://localhost:1111/forum)

and

curl -i -H ‘Host:’ [http://localhost:1111/forum](http://localhost:1111/forum)

and

curl -i -H ‘Host: [fake.example.com](http://fake.example.com)’ [http://localhost:1111/forum](http://localhost:1111/forum)

? Does any difference matter?

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![jwxie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@jwxie](https://www.ruby-forum.com/u/jwxie)\
**Post date:** [May 27, 2012, 11:56pm UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070/3 "2012-05-27T23:56:47Z")

</div>

Hi Francis,  
Thanks for the response.

After reading the documentation,  
[http://wiki.nginx.org/HttpCoreModule#.24host](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:

> **[Re: Is $http\_host dangerous?](https://forum.nginx.org/read.php?2,226866,226882#msg-226882)**
>
> 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\`

---

<div class="post-metadata">

**Author:** ![jwxie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@jwxie](https://www.ruby-forum.com/u/jwxie)\
**Post date:** [May 28, 2012, 1:21am UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070/4 "2012-05-28T01:21:38Z")

</div>

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” 😉

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. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![jwxie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@jwxie](https://www.ruby-forum.com/u/jwxie)\
**Post date:** [May 28, 2012, 2:29am UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070/5 "2012-05-28T02:29:00Z")

</div>

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](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/](http://public/)” and “curl [http://PUBLIC/](http://PUBLIC/)” will probably return different  
content, where “root /var/www/$host” would have returned the same.

Or

echo 'GET [http://public/](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. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![jwxie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@jwxie](https://www.ruby-forum.com/u/jwxie)\
**Post date:** [May 28, 2012, 12:16am UTC](https://www.ruby-forum.com/t/is-http-host-dangerous/220070/6 "2012-05-28T00:16:37Z")

</div>

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

> <https://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:

> **[Re: Is $http\_host dangerous?](https://forum.nginx.org/read.php?2,226866,226883#msg-226883)**
>
> 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\`
