PHP: filter_input with REQUEST

Asked

Viewed 1,927 times

2

As most of you know, in PHP 5.2 the function has been implemented filter_input.

I’m working quietly with her, no doubt very alarming.

The problem is that: I can work well with it, using in the first parameter the flags INPUT_GET or INPUT_POST when I need to validate using the FILTER_SANITIZE_ENCODED.

However, in the application I’m working on I also need to validate the INPUT_REQUEST (not implemented), and here comes the error.

Erro PHP filter_input 'INPUT_REQUEST'

Detail that the PHP version I’m using is 5.5.6.

I wonder if anyone knows or has any method to filter the $_REQUEST as filter_input should do.

  • Post the part of the code that is giving error.

3 answers

3

The variable $_REQUEST is a supervariable that contains the variables $_GET, $_POST and $_COOKIE, in the order defined by Directive request_order of PHP.

So I don’t see the need to use the constant INPUT_REQUEST if you know which of the other supervariables the value you want to filter is coming from.

  • The point is that sometimes, in part of the code, I make a call via ajax to a page query.php?key1=val1&key2=val2 and still step POST parameters, ie it gets GET and POST, so it would be faster to treat the request.

  • 1

    I don’t know where I read that using the variable $_REQUEST constitutes a security breach as the variable can come in three different ways. Also, if you use $_GET, $_POST or $_COOKIE, you are being explicit in your code where the variable is coming from. Personally, I see no problem in opting for one of these instead of the $_REQUEST :)

  • 2

    I was also aware of this security breach by REQUEST but I decided to try anyway, and gave up. I did a very simple function to treat this: switch ($_SERVER['REQUEST_METHOD']) {
 case 'GET':
 return filter_input(INPUT_GET, $val, FILTER_SANITIZE_ENCODED);
 default:
 case 'POST':
 return filter_input(INPUT_POST, $val, FILTER_SANITIZE_ENCODED);
 }

1

This is a fairly old topic, but since this has been brought up again I will leave two possible solutions to the problem.

As you well discovered, the functionality of INPUT_REQUEST was not implemented, so unlike suggested by Marcio, you can’t utilise filter_input_array() because you’ll have the same mistake.

The first solution is based on the function filter_var_array(). Its applicability is most appropriate when:

  • All entries can receive the same type of treatment
  • You don’t know what can come by $_REQUEST

To use function filter_var_array() you must create an associative array with the indexes present in $_REQUEST (or any other array that you need) as keys and as values the filters to be applied.

But, as we need the same dynamism provided by flag that we would use in filter_input() and filter_input_array(), we cannot create this array manually, so we will use array_combine(), array_keys() and array_fill() which together will allow the creation of a new array in Runtime, variable length and with the same $_REQUEST structure:

$args = array_combine(

    array_keys( $_REQUEST ),

    array_fill( 0, count( $_REQUEST ), FILTER_SANITIZE_ENCODED )
);

array_combine() expects two arrays as argument. One for use of keys and the other for values.

We use array_keys() to get all $_REQUEST keys and since we don’t know how many elements there are in $_REQUEST so we can assemble the necessary part, we use array_fill() creating a new array with a predefined amount of elements, obtained here counting the amount of entries in $_REQUEST. All entries will have the same value, in this case, the flag FILTER_SANITIZE_ENCODED.

And we will pass this array to filter_var_array():

$filtered = filter_var_array( $_REQUEST, $args );

This in a file accessed with a purposefully harmful URL such as http://localhost:8080/test.php?foo=<script>alert('hi');</script>, results in a var_dump() with:

array (size=1)
  'foo' => string '%3Cscript%3Ealert%28%27hi%27%29%3B%3C%2Fscript%3E' (length=49)

The second alternative is to iterate the desired array ($_REQUEST) and apply filter_var() in each entry generating a new clean array.

She’s more appropriate when:

  • Some entries cannot be validated by a flag in particular -OR- require a flag which it would not justify applying to other values
  • The array to be filtered/validated/sanitized is small, because iterating large arrays is bad for performance

    $cleansed = array();
    
    foreach( $_REQUEST as $offset => $entry ) {
        $cleansed[ $offset ] = filter_var( $entry, FILTER_SANITIZE_ENCODED );
    }
    

The output of this array will be the same above.

As for the first applicability consideration made on this second technique, you do not necessarily need to take it into consideration to opt for this technique.

You can very well use the first method and, right after creating the array to be used ($args), overwrite one or more previously known indexes manually before informing this array as argument for filter_var_array():

$args = array_combine(

    array_keys( $_REQUEST ),

    array_fill( 0, count( $_REQUEST ), FILTER_SANITIZE_ENCODED )
);

$args['algum_campo_de_URL'] = FILTER_SANITIZE_URL;

// Ou

$args['algum_campo_sem_tratamento'] = NULL;

Note: Do not remove the index with unset() otherwise the corresponding entry. instead of being kept untouched, it will be removed from the resulting array.


Now that the problem has been solved in I would like to leave a word about why using $_REQUEST might be harmful.

The so-called HTTP Verbs were created in their vast specificity to serve each one for a unique purpose. And although no browser currently respects all verbs when defined in the attribute method of a form, does not mean that you should program wrong too.

So if it’s POST, let’s use $_POST. If it’s GET, let’s use $_GET. Do we need a cookie? $_COOKIES.

Now see a hypothetical scenario where using $_REQUEST instead of one of the three correct superglobals is harmful:

Imagine a situation where you coincidentally have a variable named X that MUST pass exclusively via GET and another, also called X, exclusively by POST.

Using $_GET and $_POST, you can perfectly use the identical names. Even if it doesn’t seem very certain, sometimes by lexical harmony (I’m so horny with programming :P), it’s justifiable.

But if you encode your script entirely with $_REQUEST, one will overwrite the other and by the subtlety of the procedure, debugging would be complicated.

See an example (very pig) illustrating this:

var_dump( $_REQUEST, $_POST, $_GET );

echo '<form method="post">';
echo '<input type="hidden" name="nome" value="Bruno" />';
echo '<input type="submit" value="Vai" />';

echo '</form>';

When accessing the page for the first time there will be three empty arrays, after all there is no information yet.

Placing a GET parameter name in the URL (Bruno Augusto, to illustrate), you will see Bruno Augusto out of $_REQUEST and another out of $_GET. The second one, for $_POST, will remain empty.

Submit the form. Bruno will be shown twice and Bruno Augusto one.

That’s because $_REQUEST merges everything and, thanks to order of variables, the Bruno of the hidden field coming from $_POST will overwrite the Bruno Augusto coming from $_GET, because in superglobal arrays, they have the same index.

You are also affected by this rather subtle problem when using Javascript because GET and POST data are basically headers and are also subject to overwriting.

Still not convinced about your case by transitioning data through AJAX? Okay:

test.html

$(function(){

    $.ajax({

        method: 'post', 
        url: 'http://localhost/test.php?var1=value1',
        data: { var1: 'some content', var2: 'doh' }

    }).done( function( data ) {

        console.log( data );

    }).fail( function( xhr, status ) {

        console.log( status );
    });

});

test php.

The Answer console after the Success Request:

"{"var1":"value1"}

{"var1":"some content","var2":"doh"}

{"var1":"some content","var2":"doh"}"

var1 in $_REQUEST by default filled with var1 of $_GET was written by var1 from $_POST.

0

You can try to use filter_input_array(). For example:

$vars = array(
    'key1' => FILTER_SANITIZE_NUMBER_INT
);

$entradas = filter_input_array(INPUT_REQUEST, $vars);

echo $entradas['key1'];

Another option is to use filter_var(), the use is simple:

echo filter_var($_REQUEST['key1'], FILTER_SANITIZE_NUMBER_INT);

But remember that the filters are far from ensuring that your application is safe, you should try to parameterize your querys via PDO and escape special characters according to your database.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.