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

PHP-安全更改密码表单/方法,php,mysql,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 = do

我已经基于一篇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';

你试图做的根本上是有缺陷的。攻击者仍然可以使用JavaScript函数创建的哈希值执行重播攻击。此外,您只保护未散列的密码(但我仍然可以在rainbow表中查找),而不保护帐户。攻击者可以使用哈希值作为用户进行身份验证。这是因为哈希值是密码

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

下面是一个例子,我的名字叫爱丽丝,我正在观看鲍勃的网络流量

我(作为Alice)看到Bob提交了你的表单,然后我看到你的web服务器回复Bob说“谢谢,密码更新了”

我(作为Alice)现在知道Bob的密码,更糟糕的是,我现在可以发送Bob刚刚发送给您的相同HTTP请求,但现在由于我知道Bob的密码,我可以更改请求以再次更新密码,以满足我的任何需要


表单的安全性并不比不散列发送密码更高。

您的脚本设置为在许多情况下转发到
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);
            }

删除
标题('Location:../home.php?msg=2')在您原始脚本的本节底部。

您是否与数据库有连接?我确实与数据库有连接。是的。谢谢,我将对此进行研究。现在阅读,它应该更有意义。@MorganLane我添加了一个编辑,向您显示您应该尝试捕获mysqli错误以进行调试。一旦脚本完全运行,您就可以删除捕获错误并根据错误转发用户。谢谢,我会检查它。