How (not) to use request_var

Note: This post is focused at MOD creators and contains numerous specialized subtle elements.

Presentation

Among the immense security includes that phpBB 3.0 gives is the capacity used to handling client input, request_var. This capacity was intended to make it simple to safely recover client inputted information. It is a standout amongst the most critical security works in a framework that recovers outer information as it can (with provisos that will be expounded upon) without any assistance stop XSS and SQL infusion assaults dead in their tracks

The reason we have made this blog entry is to give more data to adjustment engineers on the best way to appropriately clarify how this functions and why you should utilize it.

SQL Injections

SQL infusions are a standout amongst the most perilous vulnerabilities a web application can have, yet are one of the least demanding vulnerabilities to anticipate. These assaults happen when information is embedded into the database without appropriately purifying. Anything from the $_GET, $_POST, $_COOKIE, or $_SERVER clusters ought to be considered client input and require sterilizing.

To forestall SQL infusions, legitimate utilization of request_var’s information writing is required.

Information composing

Keeping in mind the end goal to counteract SQL infusions on non-strings it is critical to set the information write on the info. It is completely significant to ensure the sort is the thing that you anticipate that it will be.

In request_var this is finished by throwing the second contention, the default esteem, to the sort you require.

Case use

Here is a case of how to utilize request_var. It gets client contribution by utilizing request_var and runs a SQL inquiry in light of it. Note the 0 in the request_var call, it ensures that $user_id is a number.

 

Code: Select all
$user_id = request_var('user_id', 0);

$sql = 'SELECT username
FROM ' . USERS_TABLE . '
WHERE user_id = ' . $user_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);

echo $row['username'];

Where things can go wrong

Here is an example of a mistake which can have very bad consequences.  It is based on the previous example.  Instead of defaulting to 0 we want to default to the current user’s user_id.

Code: Select all
$user_id = request_var('user_id', $user->data['user_id']);

$sql = 'SELECT username
FROM ' . USERS_TABLE . '
WHERE user_id = ' . $user_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);

echo $row['username'];

As you can see, only the first line has changed.

The vulnerability

Did you spot it? $user->data[‘user_id’] is a value that is taken directly from the database and all values from the database are strings. This means that $user_id will not be cast to an integer but instead to a string.  The consequence is that an attacker can alter the SQL query to one that retrieves or changes specific data in your database for their own use.

If, for example, an attacker wanted to get some email addresses, he could simply set the user_id GET parameter to:

Code: Select all
0 UNION SELECT user_email as username FROM phpbb_users WHERE user_id = 2

This would result in a final SQL query like this:

Code: Select all
SELECT username FROM phpbb_users WHERE user_id = 0 UNION SELECT user_email as username FROM phpbb_users WHERE user_id = 2

That would give him the email address of the user with user_id 2.  It should be pretty clear that there is a lot of bad stuff that can be done using this method.

How to do it properly

It is extremely easy to prevent this from happening, the only required change is casting the second argument of request_var to an integer.  In code this would look as follows.

Code: Select all
$user_id = request_var('user_id', (int) $user->data['user_id']);

One more note for strings

Although request_var can protect you for most types when properly used, there is still one more requirement if you are requesting a string.  That is to escape the string using the correct escaping method for your database, which is all handled correctly using the sql_escape function in the database object.

Code: Select all
$foo = request_var('foo', 'bar');
$sql = 'SELECT username
FROM ' . USERS_TABLE . '
WHERE foo = ' . $db->sql_escape($foo);

That’s it, folks!

request_var is a great tool but it needs to be used correctly, which includes casting the default value to the correct type and escaping any strings before using them in an SQL query.