在Laravel 4中,我想保护一些复杂的数据库查询不受SQL注入的影响。这些查询使用查询构建器和DB :: raw()的组合。这是一个简化的例子:
$field = 'email';
$user = DB::table('users')->select(DB::raw("$field as foo"))->whereId(1)->get();
我已经读过Chris Fidao's tutorial可以将一组绑定传递给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注入的正确方法是什么?
答案 0 :(得分:6)
我发现查询构建器有一个名为 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();
答案 1 :(得分:3)
Eloquent在引擎盖下使用PDO来清理物品。它不会清理添加到SELECT语句中的项目。
然而,mysqli_real_escape_string方法对于清理SQL字符串仍然很有用。
还考虑(或者代替)保留users表中的有效字段名称数组,并检查它以确保没有使用无效值。
$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();