Can I 100% rely on
$_SERVER to be a safe source of data that I do not need to sanitized like I do
This is taken from one of my questions on Stack Overflow: Which $_SERVER variables are safe?
These variables are set by the server environment and depend entirely on the server configuration.
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.
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.
'argc'(only applicable to CLI invocation, not usually a concern for web servers)
'REQUEST_URI'(may contain tainted data)
'PHP_SELF'(may contain tainted data i.e. /index.php/evilstring)
- any other
‡ 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.
$_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.
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
$argv, from your database, from the filesystem (aside from your version-controlled code), etc...
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.
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.
$db->query("SELECT * FROM users WHERE name = '$username'");
<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.