Search code examples
phpsecurityfilteringsanitizationfilter-var

FILTER_VALIDATE_INT validates URL encoded values as INT


Why does the query: *.php?page=%20%209999%20%20 and id est *.php?page=%0a%0d9999%0a%0d validate as INT and return as int(9999)?

$args=array('page'=>array('filter'=>FILTER_VALIDATE_INT)));
$ret=filter_input_array(INPUT_GET,$args);

var_dump($ret['page']);

Solution

  • The encoded URL is:

    *.php?page=%20%209999%20%20
    

    The decoded URL is:

    *.php?page=  9999  
    

    hence you observe int(9999). %20 and %0A are spaces and linebreaks, respectively. This behavior can be observed with the following code:

    $_GET["page"] = "  9999  ";
    $name = filter_var($_GET["page"], FILTER_VALIDATE_INT);
    var_dump($name);
    

    int(9999)

    Those URL-encoded spaces and breaks are being urldecoded before they get to your filter, and FILTER_VALIDATE_INT is not so strict with whitespace.

    One way to adjust your filter is to use a callback to be more strict with integer testing:

    $_GET["page"] = "  9999   ";
    
    function FILTER_VALIDATE_STRICT_INT($val) {
        return intval(urlencode($val)) === intval($val) ? intval($val) : false;
    }
    
    $args=array(
        'page'=>array(
            'filter'=>FILTER_CALLBACK,
            'options'=>"FILTER_VALIDATE_STRICT_INT"));
    $ret=filter_var_array($_GET, $args);
    
    var_dump($ret['page']);
    

    Returns

    bool(false)