正在阻止对仅INSERT查询执行SQL注入.这是件大事吗


Preventing SQL Injections on INSERT-only queries. Is it a big deal?

这是我第一次创建一个PHP表单,该表单将使用INSERT INTO运行MySQL查询,将数据存储在生产数据库中。这会被认为是"安全"还是过度杀戮?

$orderText = $mysqli->real_escape_string(stripslashes(htmlentities((!isset($_POST["order_text"])?"undefined":$_POST["order_text"]))));
$stmt = $mysqli->prepare("INSERT INTO testtable (order_text) VALUES (?)");
$stmt->bind_param('s',$orderText);
$stmt->execute();

我不确定缺少SELECT*会如何影响我所面临的风险,但似乎只使用INSERT的脚本更安全。是吗?

你的问题中有很多错误的假设。

  1. 这当然是小题大做
    让我们检查一下您的极其难以阅读的无数嵌套运算符语句:

    • 存储单词"undefined"毫无意义。数据库对未定义的字段有一个特殊标记,即NULL值。或者只是一个空字符串就足够了
    • 无条件的条带斜杠不会增加任何安全性,但可能会破坏数据
    • htmlentities与SQL安全无关,可能在其他方面有助于站点安全,也可能破坏数据
    • 转义不会增加安全性,还会破坏数据
  2. 你把问题从错误的方面解决了
    您的主要目标是正确设置查询的格式。不是为了防御假想的"攻击者",而是为了用最诚实的数据来发现故障。而格式正确的查询将不会受到各种攻击,只是副作用
    比如说,real_escape_string与安全性无关。它仅用于格式化字符串。查询中没有字符串(数据用引号括起来),因此此函数完全无用(甚至有害)。

  3. 事实上,通过INSERT注入的灾难性并不亚于通过SELECT注入。

最后,正确的代码是

$stmt = $mysqli->prepare("INSERT INTO testtable (order_text) VALUES (?)"); 
$stmt->bind_param('s',$_POST["order_text"]); 
$stmt->execute(); 

当将订单文本打印回站点时,使用htmlspecialchars()

仅此而已。

在第3行执行的变量绑定,通常足以防止注入攻击。绑定是个好主意,在我看来,应该总是。它不仅具有安全优势,还可以提高性能。

我认为,在第1行执行额外的解析实际上是一个缺点:它增加了复杂性,一些攻击利用了已知的数据转换,尽管使用绑定也可以缓解这些问题。

我建议将来自客户端、访问者的所有内容视为威胁。不要放松,只关注一些sql查询。养成一个好习惯是没有限制的。

我同意Charles的观点,通过绑定参数,您已经正确地逃离了变量,从而消除了SQL注入攻击的机会,并且第1行的复杂性太高了。当您跳转到PDO时,这一点会很明显,因为没有特定的$dbo->escape()调用,因为escape工作已经通过prepare()/bind()调用完成。