Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent SQL injection for queries that combine the query builder with DB::raw()

In Laravel 4, I want to protect some complex database queries from SQL injection. These queries use a combination of the query builder and DB::raw(). Here is a simplified example:

$field = 'email';
$user = DB::table('users')->select(DB::raw("$field as foo"))->whereId(1)->get();

I've read Chris Fidao's tutorial that it is possible to pass an array of bindings to the select() method, and therefore prevent SQL injection correctly, by using prepared statements. For example:

$results = DB::select(DB::raw("SELECT :field FROM users WHERE id=1"), 
               ['field' => $field]
           ));

This works, but the example puts the entire query into a raw statement. It doesn't combine the query builder with DB::raw(). When I try something similar using the first example:

$field = 'email';
$user = DB::table('users')->select(DB::raw("$field as foo"), ['field' => $field])
             ->whereId(1)->get();

... then I get an error: strtolower() expects parameter 1 to be string, array given

What is the correct way to prevent SQL injection for queries that combine the query builder with DB::raw()?

like image 460
mtmacdonald Avatar asked Oct 31 '14 09:10

mtmacdonald


People also ask

Which methods can be used to avoid SQL injection?

The only sure way to prevent SQL Injection attacks is input validation and parametrized queries including prepared statements. The application code should never use the input directly. The developer must sanitize all input, not only web form inputs such as login forms.

What is DB :: Raw?

DB::raw() is used to make arbitrary SQL commands which aren't parsed any further by the query builder. They therefore can create a vector for attack via SQL injection.

Which feature of JDBC can we use to prevent SQL injection?

To prevent SQL Injection attacks in Java, you must treat user input passed to the SQL queries as untrusted and avoid dynamic SQL queries created using simple string concatenation. If possible, you should validate input against a whitelist and use parametrized queries also known as prepared statements in Java JDBC.

Does laravel prevent SQL injection?

By default, Laravel's Eloquent ORM protects against SQL injection by parameterizing queries and using SQL bindings. For instance, consider the following query: use App\Models\User; User::where('email', $email)->get();


2 Answers

I discovered the query builder has a method called setBindings() that can be useful in this instance:

$field = 'email';
$id = 1;
$user = DB::table('users')->select(DB::raw(":field as foo"))
        ->addSelect('email')
        ->whereId(DB::raw(":id"))
        ->setBindings(['field' => $field, 'id' => $id])
        ->get();
like image 76
mtmacdonald Avatar answered Nov 07 '22 15:11

mtmacdonald


Eloquent uses PDO under the hood to sanitize items. It won't sanitize items added to SELECT statements.

The mysqli_real_escape_string method is still useful for sanitizing SQL strings, however.

Consider also (or instead) keeping an array of valid field names from the users table and checking against that to ensure there isn't an invalid value being used.

$allowedFields = ['username', 'created_at'];

if( ! in_array($field, $allowedFields) )
{
    throw new \Exception('Given field not allowed or invalid');
}

$user = DB::table('users')
            ->select(DB::raw("$field as foo"))
            ->whereId(1)->get();
like image 36
fideloper Avatar answered Nov 07 '22 14:11

fideloper