为什么这个 sql 是正确的? (sql 注入)

Why this sql is correct? (sql injection)

这是什么意思?

SELECT * from users where password = ''*'';

如果我在 mysql workbench 中检查这个,我只得到 一行 ,尽管我在 table 中有很多用户。

这 select 到底是做什么的?

有趣的问题。让我们看看 ''*'' 做了什么。

mysql> select ''*'';
+-------+
| ''*'' |
+-------+
|     0 |
+-------+

让我们创建一些用户:

mysql> select * from users;
+------+-------+
| id   | name  |
+------+-------+
|    1 | joe   |
|    2 | moe   |
|    3 | shmoe |
|    4 | 4four |
+------+-------+

并测试我们的查询:

mysql> select * from users where name = ''*'';
+------+-------+
| id   | name  |
+------+-------+
|    1 | joe   |
|    2 | moe   |
|    3 | shmoe |
+------+-------+

有趣的是,用户 4 没有被选中!但是让我们试试这个方法:

mysql> select * from users where name = 4;
+------+-------+
| id   | name  |
+------+-------+
|    4 | 4four |
+------+-------+

那么,我们可以从中推断出什么呢?

  1. ''*'' 不知何故意味着 0(我对 mysql 字符串运算符不是那么流利,所以让我们把它当作事实);
  2. MySQL,显然,在这种情况下进行类型转换。因此,如果您针对整数查询 varchar 列,它会尝试将这些字符串转换为整数并查看它是否匹配;
  3. 您只有一行 password 以 0 或非数字开头。

''*''是一个乘法:它的两个参数(空字符串)被转换为数值(即0),结果为0。然后等式左边也被转换为数字,有时会是零(当密码不能被评估为非零数字时),有时不是。

有点晦涩难懂,您可以问问自己,这是针对您的情况有意为之还是偶然行为,而实际意图是测试 '*'。有恶意的用户可能输入了 '*' 作为密码,希望您不受 SQL 注入保护,以便在没有有效密码的情况下进入系统。

  1. 您始终可以在 SQL 中使用 表达式 。比如SELECT 5-4 AS one 得到1。所以你可以看出这是一个表达式。
  2. MySQL 是一种松散类型的语言,因此它可以乘以字符串。将它们转换为数字。 '' * ''
  3. 让你归零
  4. 将字符串与数字进行比较时,MySQL 将两者都转换为数字。所以 0 = 'name' 条件会让你为真