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[]
?
- 64,406
- 24
- 178
- 215
- 419
- 1
- 4
- 4
-
1It is customary to accept good answers. You should really choose an answer for this question. – rook Nov 19 '14 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 http://www.techflirt.com/$_SERVER-in-php and also do not print on website for live user. – Ankur Kumar Singh Jul 12 '16 at 07:30
4 Answers
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.
-
+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 '13 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](http://blog.ircmaxell.com/2012/11/anatomy-of-attack-how-i-hacked.html)... – ircmaxell Mar 13 '13 at 01: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 '13 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 '14 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 http://3v4l.org/vhNTG – greggles Feb 18 '14 at 12:58
-
@Rook you might want to update based on http://stackoverflow.com/questions/6474783/which-server-variables-are-safe/6474936?noredirect=1#comment35209256_6474936, I don't have enough rep here. – Dejan Marjanović Apr 13 '14 at 17:12
-
The presence of `PHP_SELF` in the last group definitely makes me very suspicious. @rook do you know of any details (or URL) about how something like that can be manipulated ? – Radu Murzea Jan 16 '17 at 12:28
-
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...
- 1,416
- 12
- 16
-
1Your 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 '13 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](http://blog.ircmaxell.com/2012/11/anatomy-of-attack-how-i-hacked.html)). 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 '13 at 01: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 '15 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 '15 at 09:30
-
@symcbean Not sure what you mean. Sanitise if *before* it's output to browser/saved in DB/etc. – James Oct 29 '15 at 13:37
-
-
@symcbean "*we're talking about input not output*" Only as a *source* of potentially harmful data. The main question is "*Is $_SERVER[ ] a safe source of data in PHP?*" and to answer that we really need to consider output as well (imo). No matter, let's end there as we're debating low level contradictions :) – James Oct 29 '15 at 17:02
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.
- 696
- 3
- 10
-
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 09 '13 at 06:31
-
6Not 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 09 '13 at 06: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 09 '13 at 06:45
-
Don't get me wrong, I'm just trying to help you write an answer that will be both acceptable to OP and of further use to the site. I'd suggest you explain in more detail which of the $SERVER variables are safe to use, which might need sanitization and how, and which would be best altogether avoided and considered unsafe. If possible, also why. No need to list all of them IMO, just going by their prefixes should do (HTTP_, REMOTE_, SCRIPT_,...). ;) – TildalWave Mar 09 '13 at 06:50
-
4Just 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 09 '13 at 08: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. – user2079272 Mar 09 '13 at 16:02
-
-
@Ladadadada, TCP [**can** be spoofed](http://stackoverflow.com/a/4774023/632951). Just harder. – Pacerier Mar 05 '15 at 23:38
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.
- 31,973
- 8
- 71
- 135
-
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 05 '15 at 23:40