103

Any variable that a user can control, an attacker can also control and is therefore a source of an attack. This is called a "tainted" variable, and is unsafe.

When using $_SERVER, many of the variables can be controlled. PHP_SELF, HTTP_USER_AGENT, HTTP_X_FORWARDED_FOR, HTTP_ACCEPT_LANGUAGE and many others are a part of the HTTP request header sent by the client.

Does anyone know of a "safe list" or untainted list of $_SERVER variables?

Benjol
  • 63,995
  • 54
  • 186
  • 268
rook
  • 66,304
  • 38
  • 162
  • 239
  • 8
    Depends on how you define "safe". The values are all *safe* as they are, it only depends what you use them for. – deceze Jun 24 '11 at 23:45
  • 7
    I think in this context, Rook is saying "Which server variables can't be spoofed by the user", such as `REMOTE_ADDR`. – vcsjones Jun 24 '11 at 23:51
  • 6
    Anything prefaced with `HTTP_` is a request header and can be set by the browser or proxy in between. I would consider those as any other user input. – datasage Jun 24 '11 at 23:53
  • @vcsjones: `REMOTE_ADDR` can be spoofed, hijacked, or can be meaningless if client used a proxy. – bob-the-destroyer Jun 25 '11 at 00:24
  • 3
    @bob-the-destroyer REMOTE_ADDR is pulled directly from apache's TCP socket, this value **cannot be spoofed** over the Internet because of the three way handshake. – rook Jun 26 '11 at 01:39
  • 2
    @Rook: good point. I guess with the mention of "spoofing", I was more leaning towards the old act of ip spoofing itself, rather than any sort of faking the actual value of `REMOTE_ADDR`. And that would be out of the scope of this question. Good to get some insight into how this value is set though, so thanks. – bob-the-destroyer Jun 26 '11 at 22:39
  • 1
    @Rook, That depends on your SAPI. [There is no guarantee](http://php.net/manual/en/reserved.variables.server.php) that every web server will provide any of the stuff in `$_SERVER`, or even the "correct" values. – Pacerier Mar 05 '15 at 21:25

2 Answers2

157

There's no such thing as "safe" or "unsafe" values as such. There are only values that the server controls and values that the user controls and you need to be aware of where a value comes from and hence whether it can be trusted for a certain purpose. $_SERVER['HTTP_FOOBAR'] for example is entirely safe to store in a database, but I most certainly wouldn't eval it.

As such, let's divide those values into three categories:

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.

‡ See https://bugs.php.net/bug.php?id=64457, http://httpd.apache.org/docs/current/mod/core.html#usecanonicalphysicalport, http://httpd.apache.org/docs/2.4/mod/core.html#comment_999

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)
  • '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.

Community
  • 1
  • 1
deceze
  • 510,633
  • 85
  • 743
  • 889
  • Thank you, Deceze. I can't verify it's all accurate, but I can hope that it will become canonical. – Jared Farrish Jun 25 '11 at 00:13
  • @Jared Please feel free to edit if there are any inaccuracies. – deceze Jun 25 '11 at 00:15
  • @deceze - Nothing looks out of place to me, but I'm admittedly not particularly well-versed on this type of thing. – Jared Farrish Jun 25 '11 at 00:17
  • @deceze: good analysis for the basic ones. There's 20 or so more depending on the PHP version, OS or CLI vs cgi/iis/apache mod usage, but not commonly used. – bob-the-destroyer Jun 25 '11 at 00:31
  • @bob By all means, please add them. :) – deceze Jun 25 '11 at 00:36
  • @bob It (AFAIK) means the server does a DNS lookup on the `REMOTE_ADDR` IP. *How* it does this exactly and whether the DNS lookup can be attacked depends entirely on the server in question. – deceze Jun 25 '11 at 00:46
  • @deceze: sorry, my self-censored comment I think answered itself. But regarding the several other obscure `$_SERVER` values, I admittedly am not familiar with their true source, even though they appear to be safe (system paths, settings, etc). – bob-the-destroyer Jun 25 '11 at 01:00
  • Also i have no idea why you put clearly tainted variables as "reliable", i went ahead and fixed that. – rook Jun 25 '11 at 19:03
  • this is one of the hell answer there – dynamic Jun 25 '11 at 19:06
  • @deceze You have an incorrect view of security. **Everything** that comes from a user could also be coming from an attacker and is there for unsafe. – rook Jun 25 '11 at 19:30
  • 3
    @Rook But as I said, it absolutely depends on *how you use it*. Values just by themselves are neither safe nor unsafe, it depends on *what you use them for*. Even data sent from a nefarious user is perfectly safe as long as you're not doing anything with it that may compromise your security. – deceze Jun 26 '11 at 00:24
  • @deceze I am writing a patch for PHP-IDS, *they are all unsafe* for my purposes. Your list was very misleading until modification. I think that a question like this should not have a "shoot from the hip" approach, and requires some rigor. – rook Jun 26 '11 at 01:32
  • 2
    @Rook: your idea of "safe" makes this question seem a bit arbitrary, especially since it's entirely tied to an obscure extension or custom version of PHP. While you say "should not have a "shoot from the hip" approach", any answer actually seems to require at minimum familiarity with PHP sourcecode to find out how these values are set. Would emailing PHP devs not be a better approach to finding an answer? – bob-the-destroyer Jun 26 '11 at 22:51
  • @bob-the-destroyer acutally my mind is completely blown. I thought i could just say "safe" and nothing else and everyone would immediately understand it. But i should have realized that people don't have a clue what a taint or what a sink is, and are really just wondering around blind implementing vulnerabilities as they go. – rook Jun 27 '11 at 23:00
  • 2
    @Rook: Miscommunication. As deceze hinted at, "safe for what purpose". As I hinted at, your purpose is unknown, and besides there are several other undocumented `$_SERVER` values depending on how the file is served. In my opinion, the documented ones don't clarify the true source. Otherwise I believe you wouldn't be asking this question. Glad you got a list you can use. But I'd still suggest submitting a bug report (when their bug site is fixed), sending doc maintainers an email, or updating the docs yourself (if you're privy to the link). It would benefit the community to know this info. – bob-the-destroyer Jun 30 '11 at 02:26
  • 3
    `SERVER_NAME` is not necessarily controlled by the server. Depending on gateway and settings it may be duplicated from `HTTP_HOST` and hence subject to the same caveat. – bobince Mar 15 '12 at 23:04
  • Be careful with `REMOTE_HOST`. It might be semi-reliable, but not safe for all purposes: its value can be controlled by the attacker. For instance, I would not recommend eval-ing it. An attacker could register a domain name with a malicious name or possibly with strange characters in it. Remember, the attacker controls the domain names, so this variable is mostly controlled by the attacker. There are of course some constraints on its value imposed by the DNS protocol, but I would be wary of relying upon that for security. – D.W. Jul 25 '12 at 19:27
  • @D.W. I did note that to some degree and I'm not sure why you'd want to `eval` it, but good point nonetheless. – deceze Jul 25 '12 at 20:19
  • this should be copied as a user comment into the php manual somewhere. – goat Nov 24 '12 at 03:26
  • 1
    @deceze @Rook Does `SERVER_PORT` need that little cross? https://bugs.php.net/bug.php?id=64457 – Dejan Marjanović Apr 13 '14 at 15:46
  • @TOOTSKI Apparently it does. Thanks! – deceze Apr 13 '14 at 17:03
  • @deceze Thanks! I have documented it in [PHP manual](http://www.php.net/manual/en/reserved.variables.server.php) right after opening the bug. Would you mind if I add legend to each variable based on your answer? – Dejan Marjanović Apr 13 '14 at 17:22
  • @TOOTSKI Sure. This would also hopefully get more eyes to look at the issue and find those special cases as you did. – deceze Apr 13 '14 at 17:25
  • @deceze, re "arbitrary"; Not entire arbitrary as they conform to a format. For instance, `QUERY_STRING` cannot contain newline characters under most sapis. – Pacerier May 20 '20 at 09:12
  • Why is `SCRIPT_NAME` not in the safe ones? – 8ctopus Jun 26 '23 at 06:16
14

In PHP every $_SERVER variable starting with HTTP_ can be influenced by the user. For example the variable $_SERVER['HTTP_REINERS'] can be tainted by setting the HTTP header REINERS to an arbitrary value in the HTTP request.

Spudley
  • 166,037
  • 39
  • 233
  • 307
Reiners
  • 141
  • 1
  • 2
  • re "arbitrary"; Not entire arbitrary as they conform to a format. For instance, `$_SERVER['HTTP_REINERS']` cannot contain newline characters under most sapis. – Pacerier May 20 '20 at 09:14