SQL 注入

SQL 注入攻击相当容易防范,但是许多应用仍然容易受到这种攻击的侵害。考虑下面的 SQL 语句:

        <?php

        $sql = "INSERT
        INTO   users (reg_username,
        reg_password,
        reg_email)
        VALUES ('{$_POST['reg_username']}',
        '$reg_password',
        '{$_POST['reg_email']}')";

        ?>
    

这个语句由 $_POST 构成,这是毫无疑问的。

假设这个语句创建了一个新帐号。用户提供了想要的用户名和邮件帐号。注册程序产生临时的密码并发送邮件到用户处用于验证邮件地址。设想用户输入下面的内容作为用户名:

        bad_guy', 'mypass', ''), ('good_guy
    

这当然不是一个合法的用户名,但是关键的地方没有数据过滤,应用程序无法判断。如果提供一个合法的邮件地址(例如 shiflett@php.net),而应用程序生成密码为 1234,SQL 语句将变为:

        
        <?php

        $sql = "INSERT
        INTO   users (reg_username,
        reg_password,
        reg_email)
        VALUES ('bad_guy', 'mypass', ''), ('good_guy',
        '1234',
        'shiflett@php.net')"; ?>
        
    

除了用合法的邮件地址创建了一个帐号(good_guy),应用程序还创建了第二个帐号(bad_guy),用户提供了所有关于这个帐号的信息。

虽然这个特殊的例子看起来并没有什么很大的伤害,不过一旦攻击者可以修改 SQL 语句会造成多么大的损失也是相当明确的。

例如,相对于使用的数据库,可能允许一次向数据库服务器发送多个查询。因此,用户可以用分号终结当前查询,并且在其后跟随用户定义的查询。

新版本的 MySQL 允许多个查询,但是需要对应的 PHP 扩展(ext/mysqli)中的特定函数来发送多个查询(mysqli_multi_query() 来代替 mysqli_query())。只允许单一查询是更安全的,因为这限制了攻击者可能会做的事情。

防范 SQL 注入是很简单的: