32

Can I 100% rely on $_SERVER[] to be a safe source of data that I do not need to sanitized like I do $_GET[] and $_POST[]?

2
  • 1
    It is customary to accept good answers. You should really choose an answer for this question.
    – rook
    Nov 19, 2014 at 16:00
  • You can use but the data comes from http header in $_SERVER should not be used blindly. You may refer for different class of data exposed in $_SERVER techflirt.com/$_SERVER-in-php and also do not print on website for live user. Jul 12, 2016 at 7:30

4 Answers 4

51

This is taken from one of my questions on Stack Overflow: Which $_SERVER variables are safe?

Server controlled

These variables are set by the server environment and depend entirely on the server configuration.

  • 'GATEWAY_INTERFACE'
  • 'SERVER_ADDR'
  • 'SERVER_SOFTWARE'
  • 'DOCUMENT_ROOT'
  • 'SERVER_ADMIN'
  • 'SERVER_SIGNATURE'

Partly server controlled

These variables depend on the specific request the client sent, but can only take a limited number of valid values, since all invalid values should be rejected by the web server and not cause the invocation of the script to begin with. Hence they can be considered reliable.

  • 'HTTPS'
  • 'REQUEST_TIME'
  • 'REMOTE_ADDR' *
  • 'REMOTE_HOST' *
  • 'REMOTE_PORT' *
  • 'SERVER_PROTOCOL'
  • 'HTTP_HOST'
  • 'SERVER_NAME'
  • 'SCRIPT_FILENAME'
  • 'SERVER_PORT'
  • 'SCRIPT_NAME'

* The REMOTE_ values are guaranteed to be the valid address of the client, as verified by a TCP/IP handshake. This is the address where any response will be sent to. REMOTE_HOST relies on reverse DNS lookups though and may hence be spoofed by DNS attacks against your server (in which case you have bigger problems anyway). This value may be a proxy, which is a simple reality of the TCP/IP protocol and nothing you can do anything about.

† If your web server responds to any request regardless of HOST header, this should be considered unsafe as well. See How safe is $_SERVER[“HTTP_HOST”]?.
Also see http://shiflett.org/blog/2006/mar/server-name-versus-http-host.

Entirely arbitrary user controlled values

These values are not checked at all and do not depend on any server configuration, they are entirely arbitrary information sent by the client.

  • 'argv', 'argc' (only applicable to CLI invocation, not usually a concern for web servers)
  • 'REQUEST_METHOD'
  • 'QUERY_STRING'
  • 'HTTP_ACCEPT'
  • 'HTTP_ACCEPT_CHARSET'
  • 'HTTP_ACCEPT_ENCODING'
  • 'HTTP_ACCEPT_LANGUAGE'
  • 'HTTP_CONNECTION'
  • 'HTTP_REFERER'
  • 'HTTP_USER_AGENT'
  • 'AUTH_TYPE' §
  • 'PHP_AUTH_DIGEST' §
  • 'PHP_AUTH_USER' §
  • 'PHP_AUTH_PW' §
  • 'PATH_INFO'
  • 'ORIG_PATH_INFO'
  • 'REQUEST_URI' (may contain tainted data)
  • 'PHP_SELF' (may contain tainted data i.e. /index.php/evilstring)
  • 'PATH_TRANSLATED'
  • any other 'HTTP_' value

‡ May be considered reliable as long as the web server allows only certain request methods.

§ May be considered reliable if authentication is handled entirely by the web server.

The superglobal $_SERVER also includes several environment variables. Whether these are "safe" or not depend on how (and where) they are defined. They can range from completely server controlled to completely user controlled.

8
  • +1 This is exactly the answer I was thinking of and referring to what it should contain in comments to @GBC. I hope it's what OP requires. At a first glance at $SERVER variables (PHP manual), I did think that they could be grouped security-wise by their name prefix, but you've clearly shown that's not the case with all of them. I'm glad there's no need to write this from scratch, as it would apply to pretty much all web frameworks out there (names of variables might be slightly different, but equal in function) :)
    – TildalWave
    Mar 10, 2013 at 22:41
  • @Rook: Minor note, but relying upon REMOTE_ADDR requires that your web server be properly configured as well. Sometimes it can be controlled...
    – ircmaxell
    Mar 13, 2013 at 1:18
  • @ircmaxell that is a cool attack that has come up in discussions with my pentesting buddies. One of my friends just sets these headers on every engagement hoping to get lucky after reading that blog post.
    – rook
    Mar 13, 2013 at 15:50
  • This talks about controlling the variables, but there are two important and distinct elements of the variables: their content and their data type. Can you clarify if you believe it's possible for a client to set the data type of any of these to anything other than a string?
    – greggles
    Feb 17, 2014 at 14:49
  • Or rather, what specific data types can it contain. AFAIU, they can be either strings or arrays, but not bools nor objects nor ints. This is important because 3v4l.org/vhNTG
    – greggles
    Feb 18, 2014 at 12:58
15

Can I 100% rely on $_SERVER[] to be a safe source of data that I do not need to sanitized like I do $_GET[] and $_POST[]?

Your question immediately indicates failure. All sources of input must be sanitized. Input is not just considered channels that the user can directly control, but all sources of data outside of your application.

Think of it this way, your application has 2 ways of getting data: information that's hard coded in your application, and input. Even if it's generated by another program on the same system, it's still input to your program.

The common idiom Filter-In, Escape-Out applies not just to user input, but to anything that enters and leaves your application.

So if it's in $_SERVER, it MUST be filtered/sanitized. You should never rely upon anything that is not hard-coded in your application.

Why is this important? Let's imagine that you filter all input from the user, but then trust data that comes from your database. If I can exploit a hole in your filtering, I can inject data that then becomes trusted. This can result in second-order XSS or SQLi. But if you filter everything that comes into your application, when it comes in, regardless of where it comes from, then you'd be safe!

So no, you can never 100% rely upon anything in $_SERVER, $_GET, $_POST, $_COOKIE, $_REQUEST, $_ENV, $argc, $argv, from your database, from the filesystem (aside from your version-controlled code), etc...

7
  • 1
    Your answer immediately indicates failure. It's relatively difficult to compromise PHP by hitting it with bad data (there are some historical vulnerabilities) but it makes no sense to modify the representation of the data after it has been parsed. You should ALWAYS change the representation of data before it leaves PHP - but how you change it depends on where it is going (htmlentities, urlencode, mysqli_real_escape_string....) or do you process all your data base64 encoded? (which BTW is not URL safe). YOU DONT SANITIZE INPUT - VALIDATING IT IS OK - YOU ALWAYS ESCAPE OUTPUT
    – symcbean
    Mar 12, 2013 at 21:40
  • 1
    @symcbean: I think you missed the point of my post. My point was that you should never trust anything outside of the source code of your application. This includes things coming from external sources that you "supposedly" can trust (like REMOTE_ADDR). Sure, it's hard to compromise PHP itself, but I was talking about second and third order compromises which leverage bugs (which can exist anywhere) and the nature that your app uses trusted data. Trust nothing is the only safe way to write code...
    – ircmaxell
    Mar 13, 2013 at 1:15
  • @symcbean "It's relatively difficult to compromise PHP by hitting it with bad data" You did not say the word "impossible" and therefore it is "possible" (however unlikely) for compromise and so protection "might be" necessary. Whether to sanitise $_SERVER depends on a few things, and without that explicit knowledge answers here can only be guidelines - i.e. do you own/manage the server, what is the application size/purpose? etc.
    – James
    Oct 28, 2015 at 22:57
  • @James: What kind of sanitization in a PHP script is going to protect the system from data it has already parsed?
    – symcbean
    Oct 29, 2015 at 9:30
  • @symcbean Not sure what you mean. Sanitise if before it's output to browser/saved in DB/etc.
    – James
    Oct 29, 2015 at 13:37
6

Not a silly question at all!

Many (but not all) of the $SERVER variables are passed from the users browser (or can be influenced by the user), for example the QUERY_STRING, REQUEST_URI and all of the HTTP_* variables.

Even the REMOTE_ADDR variable can be spoofed using raw sockets (although only with valid IPs as far as I'm aware).

I'd escape them all as a matter of good policy.

http://php.net/manual/en/reserved.variables.server.php

8
  • Pretty pointless to mention REQUEST_URI as 'something that can be influenced by the user'. Also, there's actually a lot of entirely safe (server-side only) and useful variables that can be read through $SERVER, like local paths, self-referencing variables,... and other 'transparent' (can't be spoofed, self-obvious but useful) variables such as protocol, method, query string, query parameter values, query parameter names, that are as safe to use as is to interpret them (which might or might not be the case, depends on sanitization).
    – TildalWave
    Mar 9, 2013 at 6:31
  • 6
    Not really pointless, since this is what he was asking about. It may be obvious to you that someone could attempt SQL injections by calling say "index.php?something={anything here}", but it may not be to OP. If a dev has simply put an unsanitized $_SERVER['REQUEST_URI'] into an SQL query, that's definitely a problem.
    – GBC
    Mar 9, 2013 at 6:40
  • Agreed on the second part, but the OP was asking about sanitizing these and while there's a lot of them in the list that would have to be, there's also a lot of them that wouldn't have to or are impossible to (at the web application level at least). I was also merely trying to say your wording seems a bit awkward, as URI obviously is something user can change, but it can not be spoofed in a way that what URI is requested will somehow cause some other URI to be processed server-end. Same goes for a lot of other values in the list. And a lot of them are exclusively server-side only, too.
    – TildalWave
    Mar 9, 2013 at 6:45
  • 4
    Just one small correction: REMOTE_ADDR can't be spoofed "using raw sockets" unless your web server accepts requests over UDP and even then it must still be a real IP address. It can however be attacker-controlled if you use Apache modules such as mod_rpaf or mod_remoteip depending on how you configure them. Also with certain common Nginx config options. With these options, it's just a string (pulled from the X-Forwarded-For: header and can contain anything.
    – Ladadadada
    Mar 9, 2013 at 8:33
  • 1
    @GBC Actually it is obvious to me that script injections are possible through GET and POST. I was asking about SERVER because those are non-obvious. Mar 9, 2013 at 16:02
3

There is no such thing as "a safe source of data". You should always make sure data is in the correct format when passing it on to something else.

If you are outputting to SQL inside an apostrophe (') delimited string[1], you should escape apostrophes (or anything else that may break out the string). If you are outputting to a Javascript apostrophe delimited string[2], you should escape both any HTML and apostrophes. It all depends on what you are outputting to. A perfectly safe string can break the target script, even if not in a malicious way. (Often though, if it can be broken, it can also be exploited.)

[1] Example: $db->query("SELECT * FROM users WHERE name = '$username'");
[2] Example: <script>alert('Hi <?php echo $username;?>');</script>

I've talked about this escaping on my blog, though my post is specifically about XSS I think the same principle applies here too: What is XSS and how to protect your website.

Unless you know that PHP itself already enforces a specific format, and you can almost never be sure of that, you can consider everything unsafe. IP addresses usually come in the format x.x.x.x, but it may also be x:x:x:x:x:x:x:x for IPv6. Or even 0:0:0:0:0:ffff:x.x.x.x for IPv4 destinations in IPv6 packets. If you aren't aware of this, it may lead to some very interesting bugs.

Now an IP address will never contain an apostrophe, right..? Well there are those people checking for the $_SERVER["HTTP_X_FORWARDED_FOR"] header before using the remote address. This is great, so long as the header is set correctly (as also pointed out by @Ladadadada in a comment to @GBC's response), but that may also be a spoof. Then when you use the data that others stored in the database, you might be getting malicious stuff back... So in the end, just never trust input. Better secure it too much than forgetting it once.

1
  • Data you write using tools you trust can be considered a safe source of data if they are read using tools you trust and if no one else has permission to touch them. If that isn't safe, then you have a bigger problem.
    – Pacerier
    Mar 5, 2015 at 23:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .