tags:

views:

1385

answers:

4

I did a lot of searching and also read the PHP $_SERVER man page. Do I have this right regarding which to use for my PHP scripts for simple link definitions used throughout my site?

$_SERVER['SERVER_NAME'] is based on your web servers' config file (Apache2 in my case), and varies depending on a few directives: (1) VirtualHost, (2) ServerName, (3) UseCanonicalName, etc.

$_SERVER['HTTP_HOST'] is based on the request from the client.

Therefore, it would seem to me that the proper one to use in order to make my scripts as compatible as possible would be $_SERVER['HTTP_HOST']. Is this assumption correct?

Followup comments:

I guess I got a little paranoid after reading this article and noting that someone said "they wouldn't trust any of the $_SERVER vars":

http://markjaquith.wordpress.com/2009/09/21/php-server-vars-not-safe-in-forms-or-links/

and also:

http://www.php.net/manual/en/reserved.variables.server.php (comment: Vladimir Kornea 14-Mar-2009 01:06)

Apparently the discussion is mainly about $_SERVER['PHP_SELF'] and why you shouldn't use it in the form action attribute without proper escaping to prevent XSS attacks.

My conclusion about my original question above is that it is "safe" to use $_SERVER['HTTP_HOST'] for all links on a site without having to worry about XSS attacks, even when used in forms.

Please correct me if I'm wrong.

+1  A: 

That’s probably everyone’s first thought. But it’s a little bit more difficult. See Chris Shiflett’s article SERVER_NAME Versus HTTP_HOST.

It seems that there is no silver bullet. Only when you force Apache to use the canonical name you will always get the right server name with SERVER_NAME.

So you either go with that or you check the host name against a white list:

$allowed_hosts = array('foo.example.com', 'bar.example.com');
if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) {
    header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
    exit;
}
Gumbo
Lol, I read that article and it didn't really seem to answer my question. Which one do the pro devs use? If either.
Jeff
Iiiiinteresting, I never knew SERVER_NAME used the user-supplied values by default in Apache.
R. Bemrose
A: 

The major difference between the two is that $_SERVER['SERVER_NAME'] is a server controlled variable, while $_SERVER['HTTP_POST'] is a user-controlled value.

The rule of thumb is to never trust values from the user, so $_SERVER['SERVER_NAME'] is the better choice.

As Gumbo pointed out, Apache will construct SERVER_NAME from user-supplied values if you don't set UseCanonicalName On.

Edit: Having said all that, if the site is using a name-based virtual host, the HTTP Host header is the only way to reach sites that aren't the default site.

R. Bemrose
Understood. My hangup is "how could a user alter the value of $_SERVER['HTTP_HOST']?" Is it even possible?
Jeff
A user can alter that because it's just the contents of the Host header from the incoming request. The main server (or the VirtualHost bound to __default__:80) will respond to all unknown hosts, thus the contents of the Host tag on that site could be set to anything.
R. Bemrose
Note that IP-based virtual hosts will ALWAYS respond on their specific IP, so you cannot **under any circumstances** trust the HTTP Host value on them.
R. Bemrose
+1  A: 

Use either. They are both equally (in)secure, as in many cases SERVER_NAME is just populated from HTTP_HOST anyway. I normally go for HTTP_HOST, so that the user stays on the exact host name they started on. For example if I have the same site on a .com and .org domain, I don't want to send someone from .org to .com, particularly if they might have login tokens on .org that they'd lose if sent to the other domain.

Either way, you just need to be sure that your webapp will only ever respond for known-good domains. This can be done either (a) with an application-side check like Gumbo's, or (b) by using a virtual host on the domain name(s) you want that does not respond to requests that give an unknown Host header.

The reason for this is that if you allow your site to be accessed under any old name, you lay yourself open to DNS rebinding attacks (where another site's hostname points to your IP, a user accesses your site with the attacker's hostname, then the hostname is moved to the attacker's IP, taking your cookies/auth with it) and search engine hijacking (where an attacker points their own hostname at your site and tries to make search engines see it as the ‘best’ primary hostname).

Apparently the discussion is mainly about $_SERVER['PHP_SELF'] and why you shouldn't use it in the form action attribute without proper escaping to prevent XSS attacks.

Pfft. Well you shouldn't use anything in any attribute without escaping with htmlspecialchars($string, ENT_QUOTES), so there's nothing special about server variables there.

bobince
A: 

Hi,

I am not sure and not really trust $_SERVER['HTTP_HOST'] because it depend on header from client. In another way, if a domain requested by client is not mine one, they will not getting into my site because DNS and TCP/IP protocol point it to the correct destination. However I don't know if possible to hijack the DNS, network or even Apache server. To be safe, I define host name in environment and compare it with $_SERVER['HTTP_HOST'].

Add SetEnv MyHost domain.com in .htaccess file on root and add ths code in Common.php

if (getenv('MyHost')!=$_SERVER['HTTP_HOST']) {
  header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
  exit();
}

I include this Common.php file in every php page. This page doing anything required for each request like session_start(), modify session cookie and reject if post method come from different domain.

CallMeLaNN