Sanitize request input parameters and values
Filter out non-allowed parameters in the request input and protect parameter values against XSS.
- https://gist.github.com/stemar/6dfd81e08243e704ca0ceb3b537fcf58
- https://www.php.net/manual/en/function.filter-var-array.php#128130
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 offilter_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()
andtrim()
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 theinput[type="submit"]
value)email
: removed HTML tags and trimmed valuearray
: removed HTML tags two levels deepfull_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 neededother
: 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"
}