Sanitize request input parameters and values

Filter out non-allowed parameters in the request input and protect parameter values against XSS.

Goal

The request input array, a.k.a. the URL parameters, a.k.a. the URI query, needs to be filtered before processing.

http://example.com/index.php?full_name=`Shorty`%20O'Reilly&email=%20<script>alert('xss');</script>%20&array[][]=<b>10</b>&submit=Send
                            |--------------------------------------------------------------------------------------------------------|
                                                                            This part

We want to:

  • filter only the params we want; filter out the ones we don't want
  • trim allowed param values of white space left and right of the value
  • remove/strip HTML tags from param values to prevent Cross Site Scripting (XSS) injection

And we want to recursively clean all allowed param values in the input array.

Code

We use filter_input_array() to filter parameter keys and recursively sanitize all values.

This is the basic sanitization of a URI query for HTTP requests of any web page.

function sanitize_input_array($type, array $allowed_params) {
    return filter_input_array($type, array_fill_keys($allowed_params, [
        'filter' => FILTER_CALLBACK,
        'options' => function ($value) {
            return trim(strip_tags($value));
        }
    ]));
}
  • For the $type argument, use the same value as for the $type argument of filter_input_array():
    • INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV,
  • array_fill_keys() ensures that all allowed params are provided with the same filter callback.
  • strip_tags() and trim() are executed on each value.

Example

http://example.com/index.php?full_name=`Shorty`%20O'Reilly&email=%20<script>alert('xss');</script>%20&array[][]=<b>10</b>&submit=Send
$get = sanitize_input_array(INPUT_GET, ['submit', 'full_name', 'email', 'array', 'other']);

OR

$post = sanitize_input_array(INPUT_POST, ['submit', 'full_name', 'email', 'array', 'other']);

Result

  • submit: raw value (we assume this is the input[type="submit"] value)
  • email: removed HTML tags and trimmed value
  • array: removed HTML tags two levels deep
  • full_name: the encoded space %20 is decoded and the special characters are preserved; additional filtering would escape them or convert them to HTML entities as needed
  • other: is present in the allowed params but absent from the URI query, so the param key is included with a NULL value
var_dump($get);
array(6) {
  'submit' =>
  string(4) "Send"
  'email' =>
  string(13) "alert('xss');"
  'array' =>
  array(1) {
    [0] =>
    array(1) {
      [0] =>
      string(2) "10"
    }
  }
  'full_name' =>
  string(17) "`Shorty` O'Reilly"
  'other' =>
  NULL
}

GET query example

Assuming:

http://example.com/index.php?hex_code=d45ae654fbc6&bool=1&int_id=123&xss=%20<script>alert('xss');</script>%20
// Sanitize the allowed params
$get = sanitize_input_array(INPUT_GET, ['hex_code', 'bool', 'int_id']);

// Check if `xss` has been filtered out
assert(!isset($get['xss']));

// Validate `hex_code`
$get['hex_code'] = filter_var($get['hex_code'], FILTER_CALLBACK, [
    'options' => function ($value) {
        return ctype_xdigit($value) ? $value : false;
    }
]);

// Validate `bool`
$get['bool'] = filter_var($get['bool'], FILTER_VALIDATE_BOOLEAN);

// Validate `int_id`
$get['int_id'] = filter_var($get['int_id'], FILTER_VALIDATE_INT);

// Check for filter errors
if ($get['hex_code'] === false || $get['int_id'] === false) {
  // Display error message or return 400 Bad Request
  return http_response_code(400);
}

// Now, $get contains sanitized & validated values
var_dump($get);
array(3) {
  'hex_code' =>
  string(12) "d45ae654fbc6"
  'bool' =>
  bool(true)
  'int_id' =>
  int(123)
}

Define reusable callback

function validate_hex_callback($value) {
    return ctype_xdigit($value) ? $value : false;
}

$get['hex_code'] = filter_var($get['hex_code'], FILTER_CALLBACK, ['options' => 'validate_hex_callback']);

Define a specific validation filter function

function validate_hex_var($value) {
    return filter_var($value, FILTER_CALLBACK, ['options' => 'validate_hex_callback']);
}

$get['hex_code'] = validate_hex_var($get['hex_code']);

POST request example

Assuming:

<input type="text" name="email" value="admin@example.com">
<input type="submit" name="submit" value="submit">
// Sanitize the allowed params
$post = sanitize_input_array(INPUT_POST, ['submit', 'email']);

// Validate `submit` as boolean to determine if form is submitted
$post['submit'] = filter_var($post['submit'], FILTER_CALLBACK, [
    'options' => function ($value) {
        return $value === 'submit';
    }
]);

// Validate `email`
$post['email'] = filter_var($post['email'], FILTER_VALIDATE_EMAIL);

// Check for filter errors
if ($post['email'] === false) {
  // Display error message or return 400 Bad Request
  return http_response_code(400);
}

// Now, $post contains sanitized & validated values
var_dump($post);
array(2) {
  'submit' =>
  bool(true)
  'email' =>
  string(17) "admin@example.com"
}