Responsible use of the $_REQUEST variable.

A recent thread split on the PHP Internals list has been about the use of the $_REQUEST variable. I have seen more than one person make the following logic mistake:

  1. I may get data via GET
  2. I may get data via POST
  3. Ah, I should use $_REQUEST as it will catch both.

There is a problem with that logic. Cookies! Cookies are also put ino $_REQUEST. In fact, they are put into $_REQUEST last. So, any data that was sent via GET or POST is overwritten by cookies of the same name.

When does this cause a problem? Well, let’s say you have a script that has a form that asks for a user name. You call the field username. So, you are looking for that data in $_REQUEST. Unknown to you, another member of your team makes a cookie named username on a totally unrelated application. His cookie needs to be accessible from several parts of the site, so he assigned the cookie to the path /. So, now, when a user submits your form, the data comes in looking like this:

$_GET["username"] = "user input";
$_COOKIE["username"] = "Tom";
$_REQUEST["username"] = "Tom";

So, now you have bad data for the username you wanted. This becomes even more menacing when you start thinking about security issues like XSS or CRSF. As Stefan Esser, a strong PHP Security advocate, wrote in another reply to the thread:

Just imagine my example…

switch ($_REQUEST['action'])
{
case 'logout':
logout();
break;
...
}

When someone injects you a cookie like +++action=logout through an
XSS or through a feature like foobar.co.kr can set cookies for *.co.kr
(in FF atleast).
Then you CANNOT use the application anymore. This is a DOS. You cannot
defeat this problem except detecting and telling the user to delete his
cookies manually…

Yikes! So, now you have all kinds of problems with using $_REQUEST.

So, what is the best way to handle both GET and POST data? Well, here are a couple options.

Merge GET and POST data

You could use array_merge() to merge the $_GET and $_POST variables into one. I would use a new variable for this data. You can overwrite super globals. Some think it is a bad idea. I can’t argue that it could cause confusion if you did this in an environment where several parts of the application are going to be using user input. If you do want to do this you could do the following.

$user_input = array_merge($_GET, $_POST);
// or overwrite $_REQUEST - not recommended
$_REQUEST = array_merge($_GET, $_POST);

Use GET OR POST, not both

I personally like to only use either $_GET or $_POST. I have very rarely seen a case where using both made sense.  I normally favor $_POST if it is set.

if(!empty($_POST)){
$user_input = $_POST;
} elseif {
$user_input = $_GET;
}

Now we have a save array that can be used and we know that the data only came from one place.

About these ads

17 Responses to Responsible use of the $_REQUEST variable.

  1. Davey Shafik says:

    Or… you could just change the variables_order to ECGPS

    – Davey

  2. Dashifen says:

    Is it really that hard to remember what method by which the visitor is submitting data to another page? Why not, then, just use $_GET or $_POST as necessary based on the needs of a specific page? I don’t ask these questions to be snarky, I’m just confused about the need to use the above technique.

  3. Stefan Esser says:

    If you change the variables_order to ECGPS this might be cool with your application, but it is an absolute no go for the world outside.

    Putting the Cookie first into _REQUEST means that Cookie data is overwritten by GET and POST. This means that if you read the session id from _REQUEST a single URL is enough to overwrite your current session id with one injected through the URL. Session Fixation made easy…

  4. sapphirecat says:

    I have never found any use for _REQUEST. It’s like pouring water, beer, and sewage all into one bucket: now nothing is useful, because it’s all polluted or diluted with something else.

    Furthermore, I always want to handle GET and POST differently, because either I’m making a change of state, or I’m not. I need two different code paths, and neither of them should pay any attention to the others’ variables. (Which would be forced on me if I used _REQUEST.)

    What I’ve learned is this: the less of a mess you make with your data, the easier it is to understand, change, and audit the entire system. You have to hold less in mind to understand cleaner data, and the rest follows from that improvement.

  5. doughboy says:

    @sapphirecat:
    I agree, I never use $_REQUEST. One place I need to switch between GET and POST is in Phorum. We have a common set of code that checks input data and loads the appropriate forum’s settings based on the GET or POST data. Since it is a common part of the code, the data could come from links (i.e. GET data) or from a form (i.e. POST data).

    The other places have been where we would make an application using POST and then later we would need to hook into the middle of it via a link on another page. So, in those cases, we check POST and GET separately.

  6. Norbert says:

    Use $_GET, $_POST and $_COOKIE properly and forget about $_REQUEST once and for all. There’s no need to merge $_GET and $_POST. You always know where that specific data is coming from. Use these separate variables appropriately in your websites/applications in a consistent way and there are no issues to deal with at all.

  7. Sebs says:

    used _REQUEST and died in pain. Never touched it again ;)

  8. Lars Strojny says:

    Another way is to beat this with configuration. Assuming you have controllers, just require that every controller has an configuration entry which HTTP methods are allowed to use with this controller. /entries/1 => only GET, /entries/add => only POST, /entries/delete => only POST. No, you should not use _REQUEST then, but you can have something like a getParam()-method which accesses both _POST and _GET.

  9. EPE says:

    To Dashifen:

    No, you are not confused; but most of the rest of the world is. Unfortunately, to many people cannot tell the SEMANTIC difference between a GET and a POST request: I have seen sites developed entirely using POST and an unique URL (this is quite common among java developers), and I have seen sites where GET requests would delete data.

  10. munim says:

    hmm.. i never thought about this.
    my advice is.. you use get and post in the places where they are appropriate but remember what you have used… and use $_GET or $_POST. also you should always sanitise inputs…

  11. JordanC says:

    Don’t forget that when you use [] in POST or GET, PHP will create an array. Also, count($_POST) is quicker.

  12. JordanC says:

    Just like to say that also, automatically the use of $_GET isn’t insecure with regards to $_POST which poses a slight advantage due to it’s more “concealed” nature, but nevertheless is still as exploitable. As per the HTTP definition, GET is a useful tool for when you are passing parameters to a particular page once the user has been authenticated – to fuck around with hitten form elements when this can easily be cleansed is just ignant.

    There are so many incorrect assumptions, and many incorrect practices when cleansing GET also.

    1) Don’t remove characters like %$&^&$, you escape them to their ASCII character codes.
    2) GET requests aren’t evil, and providing you’ve got full control of the HTTP request and know what data was passed from where, you can easily ascertain if there are any errors.
    3) GET and POST exist for specific reasons. With merging GET requests with POST requests, you are able to use a central way to access elements that are the same, but also you then give precedence to whichever is prepended or appended to the array. You won’t know which came from where, and if the key in GET exists already then it’ll essentially be an intersect; as per php.net/array_merge — “If the input arrays have the same string keys, then the later value for that key will overwrite the previous one.”.

    If you want to use POST, then use POST as it was most originally intended in RFC , but essentially derived to the use of forms:

    ” The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. POST is designed to allow a uniform method to cover the following functions:”

    – Annotation of existing resources;

    – Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;

    – Providing a block of data, such as the result of submitting a
    form, to a data-handling process;

    – Extending a database through an append operation.

    The GET request is a different method, used for a different purpose and is distinctly required and shouldn’t just be noted as “insecure” due to the fact that people are able to provide simplistic SQL injection or old-school “shell injection” or XSS — all it needs to be fixed is sane code and logical checks on GET requests. Again, as per the HTTP 1.1 definition:

    ” The semantics of the GET method change to a “conditional GET” if the request message includes an If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range header field. A conditional GET method requests that the entity be transferred only under the circumstances described by the conditional header field(s). The conditional GET method is intended to reduce unnecessary network usage by allowing cached entities to be refreshed without requiring multiple requests or transferring data already held by the client.”

    Not being offensive, just saying that this isn’t neccesarily a great option or practice you can use to minimise security issues when you’re essentially obfuscating things more than you need to.

  13. […]  Responsible use of the $_REQUEST variable. (0 visite) […]

  14. Brian Moon’s Blog: Responsible use of the $_REQUEST variable

    In one of his recent blog entries, Brian Moon takes a …

  15. […] one of his recent blog entries, Brian Moon takes a look at what he considers the “proper use” of the PHP superglobal […]

  16. […] Sicherheit in PHP Responsible use of the $_REQUEST variable Ein netter Artikel über die kleinen Gefahren von _REQUEST. Die Kommentare sind ebenfalls zu […]

  17. Lawrence D'Oliveiro says:

    More examples of the crappiness of PHP language design: merging GET and POST parameters is a good idea, but mingling in cookies as well is a stupid idea. So $_REQUEST ends up doing almost, but not quite, the thing you want. And because PHP makes it too hard to do the right thing, your typical lazy PHP programmers continue to churn out poor-quality code.

    And all the suggestions for changing php.ini just add to the problem, as some have noticed. Ever wondered why no other language has the equivalent of php.ini? It’s another instance of PHP brain-death.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: