首页 > 解决方案 > 有没有办法用 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默认是支持多查询的,但是我试了一下还是不行。也许我绑定的参数错误。但我什至无法进行简单的选择查询。

标签: phpsqlmysqlisql-injectioncode-injection

解决方案


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 秒钟思考逻辑,我在登录表单中输入了一个布尔表达式作为用户名,而对于密码,我输入了随机的垃圾字符。

然后我登录了他的账户——不知道甚至试图猜测他的密码。

我不会给出我使用的确切布尔表达式,但如果您了解任何离散数学类中涵盖的基本布尔运算符优先级,您应该能够弄清楚。


推荐阅读