【问题标题】:Prevent SQL injection for bulk prepared raw query using Laravel使用 Laravel 防止对批量准备的原始查询进行 SQL 注入
【发布时间】:2016-04-10 14:22:35
【问题描述】:

这是我的查询:

$last = count($list)-1;

$sql = 'INSERT INTO table (col1, col2, col3) VALUES ';
for($i=0; $i<$last; $i++) {
    $sql .= '("'. $list[$i]['col1'] .'", "'. $list[$i]['col2'] .'", '. $list[$i]['col3'] .'), ';
}
$sql .= '("'. $list[$last]['col1'] .'", "'. $list[$last]['col2'] .'", '. $list[$last]['col3'] .') ';
$sql .= 'ON DUPLICATE KEY UPDATE ';
for($i=0; $i<$last; $i++) {
    $sql .= 'col3 = '. $list[$i]['col3'] .', ';
}
$sql .= 'col3 = '. $list[$last]['col3'];

DB::statement($sql);

不使用 PHP 的查询:

INSERT INTO table (col1, col2, col3) VALUES
    ( $list[$i]['col1'] , $list[$i]['col2'] , $list[$i]['col3'] ),
    ...
    ( $list[$i]['col1'] , $list[$i]['col2'] , $list[$i]['col3'] )

ON DUPLICATE KEY UPDATE
    col3 = $list[$i]['col3'],
    ...
    col3 = $list[$i]['col3'];

我看过thisthis。我有点不清楚我应该怎么做。我应该这样做吗?

DB::connection()->getPdo()->quote($sql);

我还读到您可以按照以下方式做一些事情:

DB::escape($sql)

使用 Laravel 防止上述查询的 SQL 注入的最好和最简单的方法是什么?

【问题讨论】:

  • 使用准备好的/参数化查询laravel.com/docs/5.2/database#running-queries
  • 你能给我举个例子,说明我将如何处理上述查询吗?如果这很重要,我也在使用 Laravel 4.2。
  • 应该很容易解释,你可以在这里找到 DB::insert for 4.2 laravel.com/docs/4.2/database#running-queries 唯一需要做的改变是将array(1, 'Dayle') 更改为一个变量,将它初始化为一个数组在查询之前并将要添加的值推送到其中(以正确的顺序)。
  • 我已经看过了。不过,我不清楚如何以这种方式编写大型准备好的查询。
  • 只要把它和你现在的完全一样,除了你将查询字符串中的所有变量都更改为占位符?,而是将变量推送到一个数组中,然后再发送到@ 987654331@方法。

标签: php mysql laravel pdo


【解决方案1】:

防止 SQL 注入的最好和最简单的方法是使用parameterised queries。 How to do it for bulk inserts 已经回答了很多次了,例如这里:Insert multiple rows with PDO prepared statements

编辑:

为了一目了然,你可以在 Laravel 中执行参数化查询

DB::insert($query, $params);

在纯 PDO 的答案中是

$stmt = DB::getInstance()->prepare($query);
$stmt->execute($params);

如何为批量插入准备$query$params 的问题已经得到解答,针对利弊进行了大量讨论,并且出现了一些针对边缘情况的替代解决方案。请阅读它们并了解其工作原理。

【讨论】:

  • 该链接很有帮助,但我想问是否有使用 Laravel 的正确方法。
  • 由于您询问的是 raw 查询,因此框架并不重要,因为您没有使用其模型层。
  • 我不认为上面的查询可以用 Laravel Eloquent 来写。我试过了,但它变成了一个 for 循环,根据 $cardQueryList 中有多少项目,它会访问数据库 n 次,所以我将其更改为准备好的原始数据,因此它只访问数据库一次。
  • 这是一个非常好的优化步骤,我给了你2个链接来回答如何安全的问题。
  • 最好我想按照@JimL 提到的方式来做。我不清楚我会如何为这样的批量声明做这件事。我想尽可能地把东西保存在 Laravel 中。
【解决方案2】:

在使用原始查询时看起来像一个问题。找到一篇很棒的文章,想把它传递给其他可能需要它的人。http://fideloper.com/laravel-raw-queries

Laravel 确实使用了 barry 提到的准备好的语句,但看起来您需要专门在绑定数组中传递变量才能在原始查询中发生这种情况。

 $someVariable = Input::get("some_variable");

$results = DB::select( DB::raw("SELECT * FROM some_table WHERE some_col = :somevariable"), array(
   'somevariable' => $someVariable,
 ));

【讨论】:

    【解决方案3】:

    我认为就是这样,除非有人可以用纯 Eloquent 做到这一点。希望这可以帮助其他尝试做类似事情的人。

    由于我使用 col1 + col2 作为键,我必须创建一个复合唯一键,如下所示:

    CREATE UNIQUE INDEX col1_col2 ON table (col1, col2)
    

    这是为了后代:

    $last = count($list)-1;
    
    $sql = 'INSERT INTO table (col1, col2, col3) VALUES ';
    $values = [];
    
    for($i=0; $i<$last; $i++) {
        $sql .= '( ?, ?, ? ), ';
        $values[] = $list[$i]['col1'];
        $values[] = $list[$i]['col2'];
        $values[] = $list[$i]['col3'];
    }
    $sql .= '( ?, ?, ? ) ';
    $values[] = $list[$last]['col1'];
    $values[] = $list[$last]['col2'];
    $values[] = $list[$last]['col3'];
    
    $sql .= 'ON DUPLICATE KEY UPDATE ';
    $sql .= 'col3 = VALUES(col3)';
    
    DB::statement($sql, $values);
    

    干杯!

    【讨论】:

    • 是的,你没看错。很少有事情需要考虑:row1 类型的名称可能会让您试图帮助的其他人感到困惑。它真的应该是filed1column1。请确保您的ON DUPLICATE 的内容完全符合您的预期,否则对试图做类似事情的人来说,您的弊大于利。
    • 我已更新为 col1、col2 等。我正在尝试使用 col1 + col2 作为键。我再去测试一下。
    • @AlexBlex 他们不在乎,他们只想用勺子喂食。 “这是我的问题 - 请为我编写代码以便它工作” RTFM 不是他们可以处理的东西
    • @ash 你知道我回答了我自己的问题,而我在这里发布的答案是我的吗?你有什么问题?如果您不想提供帮助,请不要发帖。
    • @rotaercz 我在评论 Alex Blex。我愿意通过向您和其他人展示如何为自己找到答案来提供帮助、指导和指导。所以你会进步。我绝对不会用勺子喂食,那什么也没教。
    猜你喜欢
    • 2013-06-28
    • 2018-10-23
    • 1970-01-01
    • 2020-08-20
    • 2020-12-20
    • 1970-01-01
    • 2016-10-03
    • 2015-12-12
    • 2020-09-16
    相关资源
    最近更新 更多