I\'ve seen a number of posts on here saying not to use the $_REQUEST
variable. I usually don\'t, but sometimes it\'s convenient. What\'s wrong with it?
I've been digging through some newsgroup posts on PHP Internals and found an interesting discussion about the topic. The initial thread was about something else, but a remark by Stefan Esser, a (if not the) security expert in the PHP world turned the discussion towards the security implications of using $_REQUEST for a few posts.
Citing Stefan Esser on PHP Internals
$_REQUEST is one of the biggest design weaknesses in PHP. Every application using $_REQUEST is most probably vulnerable to Delayed Cross Site Request Forgery problems. (This basically means if e.g. a cookie named (age) exists it will always overwrite the GET/POST content and therefore unwanted requests will be performed)
and in a later reply to the same thread
It is not about the fact that someone can forge GET, POST; COOKIE variables. It is about the fact that COOKIEs will overwrite GET and POST data in REQUEST.
Therefore I could infect your browser with a cookie that says e.g. action=logout and from that day on you cannot use the application anymore because REQUEST[action] will be logout forever (until you manually delete the cookie).
And to infect you with a COOKIE is so simple...
a) I could use an XSS vuln in any application on a subdomain
b) Ever tried setting a cookie for *.co.uk or *.co.kr when you own a single domain there?
c) Other cross domain whatever ways...And if you believe that this is not an issue then I can tell you that there is a simple possibility to set f.e. a *.co.kr cookie that results in several PHP versions just returning white pages. Imagine: Just a single cookie to kill all PHP pages in *.co.kr
And by setting an illegal session ID in a cookie valid for *.co.kr in a variable called +PHPSESSID=illegal you can still DOS every PHP application in korea using PHP sessions...
The discussion continues for a few more postings and is interesting to read.
As you can see, the main problem with $_REQUEST is not so much that it has data from $_GET and $_POST, but also from $_COOKIE. Some other guys on the list suggested changing the order in which $_REQUEST is filled, e.g. filling it with $_COOKIE first, but this could lead to numerous other potential problems, for instance with Session handling.
You could completely omit $_COOKIES from the $_REQUEST global though, so that it is not overwritten by any of the other arrays (in fact, you can limit it to any combination of it's standard contents, like the PHP manual on the variable_order ini setting tells us:
variable_order Sets the order of the EGPCS (Environment, Get, Post, Cookie, and Server) variable parsing. For example, if variables_order is set to "SP" then PHP will create the superglobals $_SERVER and $_POST, but not create $_ENV, $_GET, and $_COOKIE. Setting to "" means no superglobals will be set.
But then again, you might also consider not using $_REQUEST altogether, simply because in PHP you can access Environment, Get, Post, Cookie, and Server in their own globals and have one attack vector less. You still have to sanitize this data, but it's one less thing to worry about.
Now you might wonder, why does $_REQUEST exists after all and why it is not removed. This was asked on PHP Internals as well. Citing Rasmus Lerdorf about Why does $_REQUEST exist? on PHP Internals
The more stuff like this we remove, the harder it becomes for people to quickly move to newer, faster and more secure versions of PHP. That causes way more frustration for everyone than a few "ugly" legacy features. If there is a decent technical reason, performance or security, then we need to take a hard look at it. In this case, the thing we should be looking at isn't whether we should remove $_REQUEST but whether we should remove cookie data from it. Many configurations already do that, including all of my own, and there is a strong valid security reason for not including cookies in $_REQUEST. Most people use $_REQUEST to mean GET or POST, not realizing that it could also contain cookies and as such bad guys could potentially do some cookie injection tricks and break naive applications.
Anyway, hope that shed some light.
I might be used only if you want to retrieve the current url or hostname, but for actually parsing data from that URL such as parmeters using the & symbol it's probably not a good idea. In general, you don't want to use a vague description of what you are trying to do. If you need to be specific that's where $_REQUEST is bad, if you don't need to be specific then feel free to use it. I would think.
There's absolutely nothing wrong with taking input from both $_GET
and $_POST
in a combined way. In fact that's what you almost always want to do:
for a plain idempotent request usually submitted via GET, there's the possibility the amount of data you want won't fit in a URL so it has be mutated to a POST request instead as a practical matter.
for a request that has a real effect, you have to check that it's submitted by the POST method. But the way to do that is to check $_SERVER['REQUEST_METHOD']
explicitly, not rely on $_POST
being empty for a GET. And anyway if the method is POST
, you still might want to take some query parameters out of the URL.
No, the problem with $_REQUEST
is nothing to do with conflating GET and POST parameters. It's that it also, by default, includes $_COOKIE
. And cookies really aren't like form submission parameters at all: you almost never want to treat them as the same thing.
If you accidentally get a cookie set on your site with the same name as one of your form parameters, then the forms that rely on that parameter will mysteriously stop working properly due to cookie values overriding the expected parameters. This is very easy to do if you have multiple apps on the same site, and can be very hard to debug when you have just a couple of users with old cookies you don't use any more hanging around and breaking the forms in ways no-one else can reproduce.
You can change this behaviour to the much more sensible GP
(no C
) order with the request_order config in PHP 5.3. Where this is not possible, I personally would avoid $_REQUEST
and, if I needed a combined GET+POST array, create it manually.
$_REQUEST
refers to all sorts of requests (GET, POST etc..). This is sometimes useful, but is usually better to specify the exact method ($_GET, $_POST etc).
$_REQUEST
is generally considered harmful for the same reason that simple-to-medium-complexity data-transformations are often performed in the application code instead of declared in SQL: some programmers suck.
As such, if one tends to use $_REQUEST
everywhere, I can do anything via GET that I could via POST, which means setting up <img>
tags on my (malicious) site that cause users logged into your e-commerce module to purchase products silently, or I can cause them to click on links that will result in dangerous actions or the revelation of sensitive information (probably to me).
However, this is because of a novice, or at least inexperienced, PHP programmer making simple mistakes. First off, know when data of what type is appropriate. For example, I have a web service which can return responses in URLEncoding, XML or JSON. The application decides how to format the response by checking the HTTP_ACCEPT header, but can be coerced into one specifically by sending the format
parameter.
When checking the content of the format parameter, it could be sent via querystring or a postdata, depending on a multitude of factors, not the least of which being whether or not the calling applications wants "&format=json" mixed in with its request. In this case, $_REQUEST
is very convenient because it saves me having to type something like this:
$format = isset($_POST['format']) ? $_POST['format']
: (isset($_GET['format']) ? $_GET['format'] : null);
I'm not going to ramble on much further, but suffice to say that $_REQUEST
usage is not dissuaded because it is inherently dangerous - it's just another tool that does exactly what is asked of it, whether you understand those implications or not - it is the poor, lazy or uninformed decision of a poor, lazy or inexperienced programmer that causes this problem.
$_REQUEST
safelyaddslashes()
or *_escape_string()
. Going to show it back to the user? htmlentities()
or htmlspecialchars()
. Expecting numerical data? is_numeric()
or ctype_digit()
. In fact, filter_input() and its related functions are designed to do nothing but check and sanitize data. Use these tools, always.$post_clean
. Alternatively, you can just clean directly in the superglobals, but the reason I advocate using a separate variable is because doing so makes it easy to spot vulnerabilities in code, as anything pointing directly to a superglobal and not its sanitized equivalent is considered a dangerous error.In conclusion, remember this simple rule:
I strongly recommend bobince's advice: if you can, set the request_order
parameter in php.ini to "GP"; that is, no cookie component. There is almost no rational reasoning for this in 98%+ of cases, as cookie data should almost never be considered comparable to the querystring or to postdata.
P.S., Anecdote!
I knew a programmer who thought of $_REQUEST
a place to simply store data that was accessible in a superglobal way. Important usernames and passwords, paths to files, you name it and it was stored in $_REQUEST
. He was a bit surprised (although not comically so, unfortunately) when I told him how that variable behaves. Needless to say, that practice has been deposed.
I actually like using it. It gives you the flexibility to use GET or POST which can come in handy for things like search forms where most of the time data is POSTed, but sometimes you'll want to say link to a particular search, so you can use GET parameters instead.
Also, if you look at many other languages (ASP.NET for example) they make no distinction between GET and POST variables at all.
ETA:
I've never used REQUEST to get COOKIE values, but I think Kyle Butt makes a great point in the comments on this post about that. It is NOT a good idea to use REQUEST for getting COOKIE values. I believe he is right that there is some real potential for cross-site request forgery if you do that.
Also, the order in which stuff gets loaded into REQUEST is controlled by configuration parameters in php.ini (variables_order and request_order). So, if you have the same variable passed in via both POST and GET, which one actually gets into REQUEST depends on those ini settings. This could affect portability if you depend on a particular order and those settings are configured differently than you expect them to be.