php - 有没有办法用 mysqli 演示 SQL 注入?
问题描述
我想快速简单地演示一下 SQL 注入的工作原理。我已经解决了我的一些问题。我有一个包含随机用户名、密码和电子邮件的表,并且我能够“注入”SQL 代码以通过此注入查看搜索中的所有用户:
' OR '1'='1
这就是我的 PHP 代码搜索“成员”的方式:
if (isset($_POST['search'])) {
$searchterm = $_POST['searchterm'];
echo $searchterm . '<br>';
/* SQL query for searching in database */
$sql = "SELECT username, email FROM Members where username = '$searchterm'";
if ($stmt = $conn->prepare($sql)) {
/* Execute statement */
$stmt->execute();
/* Bind result variables */
$stmt->bind_result($name, $email);
/* Fetch values */
while ($stmt->fetch()) {
echo "Username: " . $name . " E-mail: " . $email . "<br>";
}
}
else {
die($conn->error);
}
}
现在我想演示一些更致命的问题,比如有人截断了你的整个表。所以我在搜索栏中尝试了这段代码:
'; TRUNCATE TABLE Members; --
但我收到此错误消息:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TRUNCATE TABLE Members; -- '' at line 1
似乎我得到了一个额外的'
,但我不知道如何摆脱它,尽管--
会评论出来。首先,我认为问题在于我后面没有空格,--
但添加空格并没有任何区别。
我曾尝试切换到 PDO,因为我认为 mysqli 不接受多个查询存在问题,但后来我在某处读到 PDO 也不支持,但我不知道。
有没有办法让它工作?
后来发现PDO默认是支持多查询的,但是我试了一下还是不行。也许我绑定的参数错误。但我什至无法进行简单的选择查询。
解决方案
mysqli_query() 默认不支持多查询。它有一个单独的功能:mysqli_multi_query()。
SQL 注入不仅仅是关于运行多个语句,尽管有著名的XKCD 卡通。
您的代码存在严重的 SQL 注入漏洞。prepare()
即使您将 $_POST 请求数据中的内容直接插入 SQL 字符串,您是否认为使用某种方式可以使查询安全?
你的代码是这样的:
$searchterm = $_POST['searchterm'];
$sql = "SELECT username, email FROM Members where username = '$searchterm'";
if ($stmt = $conn->prepare($sql)) {
/* execute statement */
$stmt->execute();
...
不安全的输入很容易以这种方式制造 SQL 注入恶作剧。它甚至可能是无辜的,但仍然会导致问题。例如,假设搜索是:O'Reilly
。将该值直接复制到 SQL 中会产生如下查询:
SELECT username, email FROM Members where username = 'O'Reilly'
看到不匹配的'
引号?这不会做任何恶意的事情,但只会导致查询失败,因为不平衡的引号会产生语法错误。
使用prepare()
不能修复意外的语法错误,也不能防止复制修改查询语法的恶意内容。
为了防止意外和恶意 SQL 注入,您应该使用如下绑定参数:
$searchterm = $_POST['searchterm'];
$sql = "SELECT username, email FROM Members where username = ?";
if ($stmt = $conn->prepare($sql)) {
$stmt->bind_param('s', $searchterm);
/* execute statement */
$stmt->execute();
...
绑定参数不会复制到 SQL 查询中。它们被单独发送到数据库服务器,并且在查询被解析之前永远不会与查询结合,因此不会导致语法问题。
至于你的问题mysqli::query()
,如果你的 SQL 查询不需要绑定参数,你可以使用它。
回复您的评论:
... 容易被注入,所以我可以向学生展示恶意攻击可能造成多大的伤害 [do]。
这是一个例子:
几年前,我是一名 SQL 培训师,在一家公司的一次培训中,我谈到了 SQL 注入。一位与会者说,“好吧,给我看一个 SQL 注入攻击。” 他递给我他的笔记本电脑。浏览器打开了他站点的登录屏幕(这只是他的测试站点,而不是真正的生产站点)。登录表单很简单,只有用户名和密码字段。
我从未见过他处理登录表单的代码,但我认为该表单是由一些代码处理的,例如大多数不安全的网站:
$user = $_POST['user'];
$password = $_POST['password'];
$sql = "SELECT * FROM accounts WHERE user = '$user' AND password = '$password'";
// execute this query.
// if it returns more than zero rows, then the user and password
// entered into the form match an account's credentials, and the
// client should be logged in.
(这是我对他的代码的有根据的猜测,我还没有看到代码。)
我花了 5 秒钟思考逻辑,我在登录表单中输入了一个布尔表达式作为用户名,而对于密码,我输入了随机的垃圾字符。
然后我登录了他的账户——不知道甚至试图猜测他的密码。
我不会给出我使用的确切布尔表达式,但如果您了解任何离散数学类中涵盖的基本布尔运算符优先级,您应该能够弄清楚。
推荐阅读
- angularjs - angularjs 在使用 POST 向服务器发送数据时导致 json 格式错误
- safari - requirejs从不同路径加载文件
- opengl - 解析 gl.xml - 不一致?
- sql-server - SSIS - 超大文件 (500MB) 因 OutOfMemory 异常而失败
- mysql - MySQL - 确定存在于给定列表中但不存在于表中的数据
- python - 如何使用 swig C++ 命名空间作为 python 模块公开
- android - 在 Android Pie 上的私有 DNS 更改时收到通知
- ios - 图像在 5 秒后自动更改
- vba - 将值从 A 到 Z 排序
- visual-studio-code - 防止 Prettier 在 Visual Studio Code 中将单行对象声明转换为多行?