在 Select X 语句中防止 SQL 注入

Preventing SQL Injection in a Select X Statement

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

SELECT email FROM users WHERE username=?

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

我希望我能得到很好的解释,我的英语不是最好的,但如果你有问题,我可以回答你的问题。另外,我确实尝试搜索过这个,但不太确定如何用文字表达,所以我没有找到与此类似的问题。

考虑到 MySQL 中的列名只是一个 (尽管请参阅此答案底部的编辑),您可以很容易地连接到 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=?'; 

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


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

因此您可以轻松做到:

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

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


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


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

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

这是一个可怕的例子:

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

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

平心而论(真正的)问题,我这样做不是为了获得代表,而是为了回答问题。

"imagining the email is a string that can destroy the database"

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

如果你使用 SELECT $email 并用 GET/POST 数组定义它并且没有转义它(注意:你不能绑定 table/column,见脚注),那么那里可能会对它进行一些操作,但你可以在使用 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 但这仍然不足以造成任何伤害。


脚注:

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

  • Can I parameterize the table name in a prepared statement?
  • Can PHP PDO Statements accept the table or column name as parameter?

关于SQL注入:

  • How can I prevent SQL injection in PHP?