PHP - 安全更改密码表单/方法

时间:2014-11-20 19:16:10

标签: php mysql

我已经根据Wikihow文章创建了自己的登录系统,我想创建一个更改密码字段,但我不知道应该怎么做。这就是我现在所拥有的:

的JavaScript

function formchange(form, current, newpass) {
    // Create a new element input, this will be our hashed password field. 
    var p = document.createElement("input");
    var p2 = document.createElement("input");

    // Add the new element to our form. 
    form.appendChild(p);
    p.name = "p";
    p.type = "hidden";
    p.value = hex_sha512(current.value);

    form.appendChild(p2);
    p.name = "p2";
    p.type = "hidden";
    p.value = hex_sha512(newpass.value);

    // Make sure the plaintext password doesn't get sent. 
    current.value = "";
    newpass.value = "";

    // Finally submit the form. 
    form.submit();
}

PHP

if (isset($_POST['cpass'], $_POST['npass'])) {
    $cpass = $_POST['cpass'];
    $npass = $_POST['npass']; // The hashed password.

    echo "Here";

    $un = getUser();

    if ($cpass == $npass) {
        echo "If";
        $random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
        $password = hash('sha512', $npass . $random_salt);

        // Insert the new user into the database 
                if ($insert_stmt = $mysqli->prepare("MYSQL UPDATE STATEMENT")) {
                    $insert_stmt->bind_param('p', $password);
                    $insert_stmt->bind_param('s', $random_salt);
                    echo "Binded";
                    // Execute the prepared query.
                    if (! $insert_stmt->execute()) {
                        header('Location: ../home.php?msg=1');
                    }
                }

        header('Location: ../home.php?msg=2');
    } else {
        // Failed
        header('Location: ../?error=1');
    }
} else {
    // The correct POST variables were not sent to this page. 
    echo 'Invalid Request';
}

它似乎无法正常工作,它继续运行home.php?msg = 2,但数据库没有更新。我对这一切都很陌生,而且我的一个项目是学习它,所以为可怕的代码道歉。我的MySQL声明是这样的:

UPDATE user_data SET user_data.password = 'p', user_data.salt = 's' WHERE username = '$un';

2 个答案:

答案 0 :(得分:1)

你要做的事情从根本上是有缺陷的。攻击者仍然可以使用JavaScript函数创建的哈希值执行重放攻击。此外,您只保护未经过修改的密码(但我仍然可以在彩虹表中查找)而不是帐户。攻击者可以使用哈希值作为用户进行身份验证。这是因为哈希值是密码。

要实际制作安全表单,您需要使用HTTPS和某种跨站点请求伪造令牌。

以下是一个例子,我的名字是Alice,我正在观看Bob的网络流量。

我(作为Alice)看到Bob提交您的表单,然后我看到您的Web服务器回复Bob说#34;谢谢,密码已更新"

我(作为Alice)现在知道Bob的密码,更糟糕的是我现在可以发送Bob刚刚发送给你的相同HTTP请求但现在因为我知道Bob的密码我可以更改更新请求密码再次,我想要的任何东西。

您的表单不比发送未经哈希的密码更安全。

答案 1 :(得分:1)

您的脚本设置为转发到home.php?msg=2许多条件,包括查询成功的时间。

if (! $insert_stmt->execute()) {
    header('Location: ../home.php?msg=1');
}

如果查询无法执行,这会将其发送到home.php?msg=1,请注意!。由于查询不会失败,脚本会继续,下一个函数是......

header('Location: ../home.php?msg=2');

"它似乎无法工作,它继续回家.php?msg = 2。 "

那么你期望脚本做什么?你是如何设计的,应该这样做。


更新新编辑

您应该避免使用这样的标头位置,否则您将永远无法找到您的错误。在开发过程中,您应该完全避免使用标头位置,尤其是在查询失败时。

我会更多地附上标题位置并抓住错误以查看语句失败的原因。我不会使用mysqli,因为在我看来,pdo更好,但我认为这应该有效。

           if ($insert_stmt = $mysqli->prepare("MYSQL UPDATE STATEMENT")) {
                $insert_stmt->bind_param('p', $password);
                $insert_stmt->bind_param('s', $random_salt);
                echo "Binded";
                // Execute the prepared query.
                if (! $insert_stmt->execute()) {
                    die($mysqli->error);
                    // header('Location: ../home.php?msg=1');
                }
                else {
                    // Success, forward
                    header('Location: ../home.php?msg=2');
                }
            }
            else {
                die($mysqli->error);
            }

删除原始脚本中此部分底部的header('Location: ../home.php?msg=2');