使用stmt prepare安全地处理表单

时间:2017-12-17 16:13:35

标签: php

prepare函数无法识别DB中已存在的成员,因此,当它应该通过else语句时,总是调用函数NewUser()?我相信这是因为当我要求它验证密码时,会遇到错误,但我不知道我做错了什么?

function NewUser(){
                    global $dbh;
                    $fullname = trim($_POST['fullname']); //at a minimus clear whitespace.
                    $username = trim($_POST['username']);
                    $email = trim($_POST['email']);
                    $user_password =  trim($_POST['password']);
                    $options = [
                        'cost' => 12, //higher = more lower= less. you want it to take around 0.4 seconds for security reasons!
                    ];

                    $hashed_password = password_hash($user_password, PASSWORD_DEFAULT, $options); // hashed password for storage!
                    $stmt = $dbh->prepare("INSERT INTO USERS(fullname, username, email, password) VALUES('$fullname', '$username', '$email', '$hashed_password')");
                    $stmt->bindValue(1,$fullname,PDO::PARAM_STR);
                    $stmt->bindValue(2,$username,PDO::PARAM_STR);
                    $stmt->bindValue(3,$email,PDO::PARAM_STR);
                    $stmt->bindValue(4,$user_password,PDO::PARAM_STR);

                    if($stmt->execute()){

                        echo "<div class= container>","<div class = \" col-md-2 connout slideInTop\">"," <span class = \"username_text\">$username</span>, <br> welcome to <br> the <br> <span class = \"vibecourt_text\">VIBECOURT</span> family! <br><br> You may <br> now sign in <br> below","</div>","</div>";
                    }
            }

            function SignUp(){

            global $dbh;

            //checking the 'user' name which is from index.php, is it empty or have some text

            if(!empty($_POST['username'])){

                    $username = trim($_POST['username']);
                    $password = trim($_POST['password']);
                    $stmt = $dbh->prepare("SELECT * FROM USERS WHERE (username = ? AND password = ?)");
                    $stmt->bindValue(1, $_POST['username'],PDO::PARAM_STR);
                    $stmt->bindValue(2, $_POST['password'],PDO::PARAM_STR);
                    $stmt->execute();
                    $selected_row = $stmt->fetch(PDO::FETCH_ASSOC);

                    //check password agaisnt stored hash
                    if(!password_verify($password, $selected_row['password'])) {    
                        NewUser(); 
                    }

                    else{
                        echo("<script>location.href = 'pages/home/home.php'</script>");
                    }
            }
            }   
            SignUp();

1 个答案:

答案 0 :(得分:0)

更新了答案

根据评论中发生的情况......似乎问题远远超出了您最初将散列密码存储到数据库中的位置。

您说您使用varchar(50)代表password_hash值。这太短了,mysql毫无疑问会削减INSERT。这将导致无法匹配的哈希值。

您应该至少有varchar(60),但PHP.net声明此哈希值会随着时间的推移而增长,建议使用varchar(255)

在这一点:

$stmt = $dbh->prepare("SELECT * FROM USERS WHERE (username = ? AND password = ?)");
$stmt->bindValue(1, $_POST['username'],PDO::PARAM_STR);
$stmt->bindValue(2, $_POST['password'],PDO::PARAM_STR);

您正尝试使用用户输入的密码(未经过哈希处理)来匹配数据库中的哈希值。

您只需删除AND password = ?bindValue即可。这样它从数据库中提取匹配的用户名条目,然后然后password_verify确定用户输入的密码是否匹配:

$username = trim($_POST['username']);
$password = trim($_POST['password']);
$stmt = $dbh->prepare("SELECT * FROM USERS WHERE username = ?");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
$stmt->execute();
$selected_row = $stmt->fetch(PDO::FETCH_ASSOC);
if(!password_verify($password, $selected_row['password'])) {    
    NewUser(); 
}

附注:虽然我不确定你是否真的想要新用户,如果他们只是输入了错误的密码???当然你会以不同的方式处理。告诉他们他们输入了错误的密码,应该再试一次。

修改

同样在你的NewUser功能中你有这个:

$stmt = $dbh->prepare("INSERT INTO USERS(fullname, username, email, password) 
                       VALUES('$fullname', '$username', '$email', '$hashed_password')");

应该是这样的:

$stmt = $dbh->prepare("INSERT INTO USERS(fullname, username, email, password) 
                       VALUES(?, ?, ?, ?)");
// ...
$stmt->bindValue(4,$hashed_password,PDO::PARAM_STR);// <- use $hashed_password