Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is casting user input to an integer sufficient to sanitize it?

Quoting from this SO answer:

Everything submitted is initially treated like a string, so forcing known-numeric data into being an integer or float makes sanitization fast and painless.

This was the sanitization method I had independently come up with for a quick and dirty query (looking up a name in a table from a numeric ID); the only variable being plugged into the query is the ID, and I know the ID should be greater than zero and less than 255, so my sanitization is as follows (with a little bit of validation thrown in too):

$id = (int)$_REQUEST['id'];
if ($id < 1 || $id > 255) errmsg("Invalid ID specified!");
$name = $DB->query("SELECT name FROM items WHERE id=${id}")->fetch_all()[0][0];

Is this sufficient to prevent SQL injection attacks or any other malicious attacks based on the user-specified value of $id, or can it still be exploited?

NOTE: the ID/name are not "sensitive", so if some input inadvertently casts to "1" or another valid ID value, I don't care. I just want to avoid antics along the lines of Little Bobby Tables.

like image 645
Doktor J Avatar asked Feb 22 '18 17:02

Doktor J


People also ask

What is sanitization of user input?

Input sanitization is a cybersecurity measure of checking, cleaning, and filtering data inputs from users, APIs, and web services of any unwanted characters and strings to prevent the injection of harmful codes into the system.

What is input sanitization in PHP?

Sanitizing data means removing any illegal character from the data. Sanitizing user input is one of the most common tasks in a web application. To make this task easier PHP provides native filter extension that you can use to sanitize the data such as e-mail addresses, URLs, IP addresses, etc.


1 Answers

The TL;DR answer is yes. When you cast to (int), you cannot get anything except an integer back.

The catch is you might have a use case where this can produce undesirable behavior. Let's take your code

$id = (int)$_REQUEST['id'];

Now, if we call this with

page.php?id=lolsqlinjection

Then the value of $id is 0 (because the string starts with a character, it will cast to 0 by default, see the PHP manual for various oddities with casting strings to integer). As such, any SQL injection is removed, making it safe from that attack vector. But you might have a use case where 0 is a special case, or another record. This is the reason prepared statements tend to be considered superior (showing MySQLi but you can do this with PDO as well)

$prep = $DB->prepare("SELECT name FROM items WHERE id=?");
$prep->bind_param('i', $_REQUEST['id']);
$prep->execute();

What this does is it tells your DB that you want the record that matches the input. As such, with my SQL injection, MySQL is now looking for an item with an integer id of "lolsqlinjection". No such record exists. Thus we avoid any potential edge cases where 0 would be a valid input.

like image 141
Machavity Avatar answered Oct 07 '22 04:10

Machavity