【问题标题】:Preventing SQL Injection in a Select X Statement防止 Select X 语句中的 SQL 注入
【发布时间】:2017-01-01 23:50:59
【问题描述】:

我不了解 SQL 注入及其工作原理。当您有用户输入信息并且您从数据库中选择输入信息与数据库中的信息匹配的数据时,我第一次开始阅读它。例如:

SELECT email FROM users WHERE username=?

现在,我了解到您设置了一个参数并且我能够成功地做到这一点,但是,我不明白是否可以从“SELECT email”部分注入 SQL,想象电子邮件是一个字符串能破坏数据库,不应该也是个问题吗?如果是这样,是否有解决办法?

我希望我能得到很好的解释,我的英语不是最好的,但如果您有问题,我可以回答您的问题。另外,我确实尝试过搜索此内容,但不太确定如何将其表达出来,因此未能找到与此类似的问题。

【问题讨论】:

  • “我不明白是否可以从“SELECT email”部分注入 SQL” - 不,除非有 WHERE 子句(或任何其他子句类型)使用未准备好的用户交互输入。
  • 理想情况下,整个 select 语句应该被参数化,所以这不应该发生。
  • “想象电子邮件是一个可以破坏数据库的字符串” - 你需要用一个例子来编辑你的问题。现在,email 是“您”选择的列,而不是用户/输入选择的列。如果您完成了SELECT $email 并使用 GET/POST 数组定义它并且没有转义它(注意:您不能绑定表/列)但您可以在之前使用 real_escape_string() 转义它或使用安全列表,只是不是有准备好的声明;那么是的,如果你不这样做,那可能(可能)会打击你。我会说我回答了这个问题;恕我直言。

标签: php mysql sql-injection


【解决方案1】:

SQL 注入是一种风险,其中不受控制的值可能成为查询的一部分。在此特定示例中,查询的“SELECT email”部分没有风险,因为 email 列中的值不是查询的一部分。

这是一个可怕的例子:

var query = "SELECT email FROM users WHERE username = '" + userInput + "'"

在该示例中,userInput 的值成为查询的一部分——用户可以输入“Blah';DROP TABLE Users”,这不会是一个好日子。但是,电子邮件列中的值不是查询的一部分。

【讨论】:

  • 这是一个糟糕的例子,因为它似乎是用 javascript 编写的?
  • 请查看有问题的标签 (:
  • 是的,我知道这些很危险,我已经学会了如何使用准备好的陈述正确地做到这一点,感谢您的回答:)
  • 如果是针对nodejs的,那么在mysql包中你可以设置占位符:username = ?并在数组中定义查询参数作为query函数的辅助参数。
  • 用错误的语言可能很好,我们不希望任何人复制这个特定的例子;)
【解决方案2】:

公平地说,对于(真正的)问题,我这样做不是为了获得声望,而是为了回答这个问题。

As per a comment I left:

“想象邮件是一个可以破坏数据库的字符串”

现在,电子邮件是“您”选择的列,而不是用户/输入选择的列,如果有的话。如果没有用户干预,那么您可以毫无问题地使用SELECT email FROM table

如果您使用SELECT $email 并使用 GET/POST 数组定义它并且没有对其进行转义(注意:您不能绑定表/列,请参见脚注),那么可能会对它进行一些操作,但是您可以使用 MySQLi 的 real_escape_string() 函数或使用安全列表将其转义,但您无法使用准备好的语句来完成。

SELECT ? FROM ? // is not allowed/not supported in any prepared statement API

但是,如果查询不涉及某种形式的 WHERE 子句,其中该变量没有被转义,那么它确实可以被操纵,但感觉可能只需要一个简单的 SELECT some_other_column_other_than_EMAIL FROM table 就可以最小化,但这仍然不会造成任何伤害。


脚注:

关于为什么你不能绑定表/列的相关链接,我觉得这是你真正想要实现的:

关于SQL注入:

【讨论】:

    【解决方案3】:

    考虑到 MySQL 中的列名只是 very limited subset of characters(尽管请参阅此答案底部的编辑),您可以很容易地连接到 SQL 字符串,但首先正则表达式删除无效字符,例如:

    //use single quotes due to dollar sign
    $column = preg_replace('/[a-z_-0-9$]/i','',$_POST['column']);
    

    然后确保它包含在引号中:

    $column = ' `'.$column.'` ';
    

    所以你可以这样做:

    $sql = 'SELECT '.$column.' FROM users WHERE username=?'; 
    

    然后将此字符串放入您的 Bind 查询中,这应该是完全安全的。


    或者,在语句的SELECT 部分,您只需删除任何特殊字符,即*.、空格和反引号操作符。

    所以你可以很容易地做到:

    $column = preg_replace("/[*`.\s]/","",$_POST['column']);   
    

    这意味着查询的 SELECT 部分只能 SELECT 并且滥用它会导致查询失败(例如使用两个 WHERE 关键字等)


    顺便说一句,让人们选择他们想要调用的列有很多潜在的陷阱,我还没有发现它在野外很常见。为什么开发者在选择选项时不清楚要选择哪些列?


    编辑:您还可以使用扩展的列名字符,这不应该影响这种方法,但值得一提的是。但是,正如我上面所说,在 99.999% 的情况下,我不认为用户应该有能力命名列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-27
      • 2012-01-05
      • 2018-08-16
      • 2011-06-12
      • 1970-01-01
      相关资源
      最近更新 更多