防止动态SQL中的SQL注入


Preventing SQL Injection in dynamical SQL

我不得不生成动态SQL。我意识到这样做会使事情变得非常复杂,下面的例子很愚蠢,显然不需要动态SQL,只是用来说明这个问题。

转义用户提供的数据是不够的,下面脚本中的第三个查询被怀疑是SQL注入。

我发现,通常最简单的方法是设计应用程序,使所有用户输入都是整数,并简单地使用(int)$_POST['user_input']对输入进行类型转换。

我现在有一个需求,其中user_input需要是文本。我应该做些什么来防止SQL注入?一个选项是PHP的ctype_alpha(),然而,我不希望"user,input"结果为FALSE,但应该保持原样或转换为"userinput"(两种场景对我来说都是好的)。我在想$user_input= preg_replace('/[^a-z0-9,]/i', '', $_POST['user_input']);之类的东西。这是100%安全的吗?

编辑

请注意,我没有执行下面的查询,而是将其插入到数据库中,因此,预处理语句不适用。你可能认为永远不应该使用动态SQL生成,但是告诉我使用准备好的语句是不对的。

<?php
$id=123;
$query='SELECT * FROM someTable WHERE someColumn="'.$_POST['user_input'].'"';
$sql='INSERT INTO meta_table (id,sql) VALUES (?,?)';
$stmt=db::db()->prepare($sql);
$stmt->execute(array($id,$query));
$sql='SELECT sql FROM meta_table WHERE id=123';
$stmt = db::db()->exec($sql);
$query=$stmt->fetchColumn();
$stmt = db::db()->exec($query); //Prone to SQL Injection
$rs=$stmt->fetchColumn();
?>

啊哈,太棒了!
最后,我设法理解了这个家伙在他的"动态sql"下是什么意思。难怪,因为它完全伪装起来,乍一看和第二看都像普通的SQL !

答案如下:

不要这样做。h1>。的"动态"SQL的想法本质上是错误的。没有人这样做。

我不知道你的具体任务,但你的解决方案显然是错误的。肯定有一个相同的方法来做到这一点。只要遵循这些简单的规则:

  • 删除meta_table
  • 删除存储在数据库中的SQL查询
  • 只从两个来源编写(或构建)应用程序中的所有查询:
    • 硬编码SQL,预先写在你的代码
    • 所有可变部件的准备报表

,让你的SQL完全安全