防止SQL注入攻击

6
我正在开发一个网站,并尝试保护连接部分安全。我对$login使用了addslashes函数来防止SQL注入,但是一些朋友告诉我这并不足够安全。然而,他们没有告诉我如何利用这个漏洞。您/你如何打破这段代码?我该如何保护它?
<?php

    if ( isset($_POST) && (!empty($_POST['login'])) && (!empty($_POST['password'])) )
    {
        extract($_POST);
        $sql = "SELECT pseudo, sex, city, pwd FROM auth WHERE pseudo = '".addslashes($login)."'";
        $req = mysql_query($sql) or die('Erreur SQL');
        if (mysql_num_rows($req) > 0)
        {
            $data = mysql_fetch_assoc($req);
            if ($password == $data['pwd'])
            {
                $loginOK = true;
            }
        }
    }
    ?>

2
谷歌 addslashes VS mysql_real_escape_string:http://www.sitepoint.com/forums/showthread.php?t=337881 - Vincent Mimoun-Prat
有很多过时的教程建议使用addslashes()作为SQL查询中转义内容的机制。如果你正在学习这些教程之一,我建议你尝试寻找更加更新和准确的资料。此外,extract($_POST)是一个漏洞的好例子;不要这样做!顺便说一句,欢迎来到StackOverflow。 - Álvaro González
几乎完全重复于 https://dev59.com/oHVD5IYBdhLWcg3wL4cA - jamesbtate
只要您使用单字节或UTF-8编码,那就足够好了。 - Your Common Sense
2
然而,您正在遭受更严重的注入攻击,这是由于extract()函数造成的。如果表单中有loginOk字段会怎样呢?.. - Your Common Sense
6个回答

14

在查询字符串输入参数时,应使用mysql_real_escape_string进行转义。使用类型转换来清理数字参数,并使用白名单来清理标识符。

在引用的PHP页面中,有一个登录表单中的SQL注入示例。

更好的解决方案是使用预处理语句,您可以通过使用PDO或者mysqli实现。


好的,你能给我一个SQL注入的例子来证明这段代码吗? 我不理解我如何能够破坏这个代码,因为我在其中转义了引号。 - Tom-pouce
mysql_real_escape_string 单独使用是不足以替代 addlashes 的。在你的代码中,这两个函数很可能没有区别。 - Your Common Sense
我已经看过这篇文章了。 但是我没有成功地破解我的代码。 你能给我一些例子吗? - Tom-pouce
李明往往会在自己不理解的主题上投票支持一个答案。 - Your Common Sense
1
关于“完全不容易受到注入攻击”的说法,你是错误的。如果你要查询 "ORDER BY $sort_field",即使没有使用 mysql_set_charset,你的 mysql_real_escape_string 的行为仍然与 addslashes 完全相同。 - Your Common Sense
显示剩余15条评论

5

你把密码以明文的方式存储,这是一个严重的安全问题。为此,至少应该使用(每个用户独有的)加盐哈希来保存密码,具体实现可以参考这里


(可以随意编辑更好的哈希和盐值解释,这是我通过快速搜索SO找到的) - Piskvor left the building

2

还有一个严重的安全漏洞 - extract。它可能会让你少打几个字符,但是会打开太多无法列举的漏洞,因为它会覆盖任何全局变量。

如果我发布这个会发生什么?

$_POST {
    'login' => 'Admin',
    'loginOK' => 1
}

猜猜看,$loginOK现在等于1了,我将作为管理员登录。

为了避免以后的麻烦,请直接使用您想要使用的变量,而不是依赖于可怕的hack extract


@Tom-pouce:不用谢。顺便说一下,这正是反对使用extract的原因——它会“凭空”创建变量(我曾经被这个问题困扰过,而且很难调试)。 - Piskvor left the building

2

使用:

mysql_real_escape_string($inputToClean);

这个函数单独被调用时除了添加反斜杠之外无法做任何更好的事情。 - Your Common Sense
1
@Col. Shrapnel:它比addslashes(Unicode表示等等)好一点点 - 但是您说得对,将其用作abracadabra-it-is-now-secure魔法粉末的程序员并不比使用addslashes更安全。 - Piskvor left the building

2
除了使用addslashes()之外,这段代码中还存在一些随机问题:
  • isset($_POST)总是TRUE,除非您从命令行运行它。您可以考虑将其删除。
  • empty()非常棘手。例如,如果$password = '0',那么empty($password)TRUE
  • 您可以这样做:if( isset($_POST['login']) && $_POST['login']!='' ){}
  • extract($_POST)是一个巨大的漏洞:任何人都可以从外部设置变量来控制您的代码。
  • $password == $data['pwd']表明您正在数据库中存储明文密码。这是一个可怕的做法。请搜索“加盐密码”。
  • 您也可以这样做:$loginOK = $password == $data['pwd'];。您知道为什么吗? ;-)

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接