防止将查询构建器与 DB::raw() 相结合的查询的 SQL 注入

问题描述 投票:0回答:3

在 Laravel 4 中,我想保护一些复杂的数据库查询免遭 SQL 注入。这些查询结合使用查询生成器和 DB::raw()。这是一个简化的示例:

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

我读过 Chris Fidao 的教程,可以通过使用准备好的语句将绑定数组传递给 select() 方法,从而正确防止 SQL 注入。例如:

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

这可行,但该示例将整个查询放入原始语句中。它没有将查询生成器与 DB::raw() 结合起来。当我使用第一个示例尝试类似的操作时:

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

...然后我得到一个错误: strtolower() 期望参数 1 为字符串,给定数组

对于将查询生成器与 DB::raw() 相结合的查询,防止 SQL 注入的正确方法是什么?

laravel laravel-4
3个回答
8
投票

我发现查询生成器有一个名为 setBindings() 的方法,在这种情况下很有用:

$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();

3
投票

Eloquent 在底层使用 PDO 来消毒物品。它不会清理添加到 SELECT 语句中的项目。

但是,mysqli_real_escape_string方法对于清理 SQL 字符串仍然有用。

还考虑(或改为)从用户表中保留有效字段名称的数组,并对其进行检查以确保没有使用无效值。

$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();

0
投票

除了能够将

setBindings()
作为独立函数与
DB::raw
一起使用之外,查询生成器的所有新“原始方法” -
selectRaw
whereRaw
havingRaw
等 - 接受一组绑定作为他们的第二个参数。尽管在相关文档中没有明确提及,但我设法弄清楚这基本上意味着您需要用问号替换有价值的 SQL 变量,然后将这些变量的值放入数组中:

$user = DB::table('users')->selectWhere("? as permissions", [admin]))->get(); 
// This will replace ? with admin

这样做可以防止暴露变量,从而防止它们被 SQL 注入和操纵。

© www.soinside.com 2019 - 2024. All rights reserved.