提交密码的最佳做法是什么?

时间:2019-03-08 05:54:40

标签: javascript php security

我正在建立一个带有用户页面的网站。目前,它是通过以下方式设置的:

用户在相应的字段中输入用户名和密码,然后按提交。

js代码使用纯文本的密码和用户名将get请求发送到php脚本。

如果凭据正确,则php将随机生成的会话令牌返回到js代码,否则返回错误消息。

现在,用户在登录时进行的所有将来交互都将要求在任何get请求中提供会话令牌。然后,PHP将检查会话令牌是否正确。

在后端,用户名与盐和盐腌密码的哈希(sha256)一起存储在数据库中。 (盐是在创建帐户时随机生成的。)

我的问题如下:上面的描述中是否有不安全的地方?如果是这样,应该怎么做。更广泛地讲,围绕网站设置用户登录页面或帐户系统的最佳实践是什么。谢谢

1 个答案:

答案 0 :(得分:1)

您为什么要重新发明轮子。

Php已经具有内置的密码加密功能,所以为什么要使用 Sha256 + Salt

它们又是两种身份验证 1.)基于会话的登录 2.)基于令牌的登录。

在撰写本文时,您将会话登录与令牌登录结合在一起。您将需要决定要申请哪一个。

因此,您需要了解许多php验证或清除功能,以确保代码更安全。

1。)使用strip_tags()

这将从表单输入或变量中删除所有html元素 例如

$email = strip_tags($_POST['email']);

2。)使用htmlentities或htmlspecialchars防止XSS攻击。

这会将htmls标记转换为它们各自的实体。仅在将结果打印或回显到html页面时使用 您将在welcome.php页面中看到我如何使用它 查看应用程序:

$email = htmlentities($_POST['email']);

3。)转义变量以防止sql注入攻击

如果使用的是Mysqli,则最好使用准备使用的sql方法Statement。 另外,您仍然可以使用 mysqli_real_escape_string()函数对变量进行转义 查看应用程序

// escape variables Against sql injections
$email = mysqli_real_escape_string($conn, $_POST['email']);

4。)如果使用基于会话的登录,则需要使用 sessionId重新生成方法。这将有助于重新生成新会话 标识为用户登录名,从而防止会话固定攻击。不用担心,您将需要在下面的login.php代码中使用它 查看应用程序:

// first you will need to initialize sessions
session_start();
session_regenerate_id();

这只是其他安全措施中的少数

让我们看看使用php密码验证功能的基于会话的登录

假设这是您的

registeration.php

<?php 
$conn = mysqli_connect("localhost","root","","demo");

if(!$conn){
    die("Connection error: " . mysqli_connect_error()); 
}

if(isset($_POST['submit'])){
        $firstName = mysqli_real_escape_string($conn,$_POST['first_name']);
        $surName = mysqli_real_escape_string($conn,$_POST['surname']);
        $email  = mysqli_real_escape_string($conn,$_POST['email']);
        $password = mysqli_real_escape_string($conn,$_POST['password']);

        $options = array("cost"=>4);
        $hashPassword = password_hash($password,PASSWORD_BCRYPT,$options);

        $sql = "insert into users (first_name, last_name,email, password) value('".$firstName."', '".$surName."', '".$email."','".$hashPassword."')";
        $result = mysqli_query($conn, $sql);
        if($result)
        {
            echo "Registration successfully";
        }
    }
?>

这就是您的 login.php 代码的样子

<?php 
$conn = mysqli_connect("localhost","root","","demo");

if(!$conn){
    die("Connection error: " . mysqli_connect_error()); 
}
if(isset($_POST['submit'])){
    $email = mysqli_real_escape_string($conn,$_POST['email']);
    $password = mysqli_real_escape_string($conn,$_POST['password']);

    $sql = "select * from users where email = '".$email."'";
    $rs = mysqli_query($conn,$sql);
    $numRows = mysqli_num_rows($rs);

    if($numRows  == 1){
        $row = mysqli_fetch_assoc($rs);
        if(password_verify($password,$row['password'])){
            echo "Password verified and ok";

// initialize session if things where ok.


session_start();
session_regenerate_id();

$_SESSION['surname'] = $row['surname'];
$_SESSION['first_name'] = $row['first_name'];
$_SESSION['email'] = $row['email'];

// take me to welcome.php page
header('Location: welcome.php');

        }
        else{
            echo "Wrong Password details";
        }
    }
    else{
        echo "User does not exist";
    }
}

?>

Welcome.php 现在看起来像下面的代码,以显示经过身份验证的用户的会话信息。

//使用htmlentities或htmlspecialchars防止XSS攻击。

<?php echo htmlentities($_SESSION['surname'], ENT_QUOTES, "UTF-8"); ?>

<?php echo htmlspecialchars($_SESSION['first_name'], ENT_QUOTES, "UTF-8"); ?>
<?php echo htmlentities($_SESSION['email'], ENT_QUOTES, "UTF-8"); ?>

现在,在我看到的帖子中,您看到在哪里写了每个http请求发送一个生成的令牌的信息。在这种情况下,我想你是 尝试减轻 CSRF攻击。

登录后,这是最好,最安全的操作方式

为防止CSRF,您需要验证一次性令牌,该令牌已过POST,并与当前会话相关联。  类似以下内容。 。

在用户请求例如插入付款记录的页面上:

payment.php

<?php
 session_start();
 $token= md5(uniqid());
 $_SESSION['payment_token']= $token;
 session_write_close();
?>
<html>
<body>
<form method="post" action="payment_save.php">
 <input type="hidden" name="token" value="<?php echo $token; ?>" />
Amount: <input type="hidden" name="token" value="100 usd" />
<input type="submit" value="submit" />

</form>
</body>
</html>

然后涉及实际插入记录:

payment_save.php

<?php
 session_start();
 $token = $_SESSION['payment_token'];
 unset($_SESSION['payment_token']);
 session_write_close();
 if ($token && $_POST['token']==$token) {
   // Insert the record for payment
 } else {
   // log message. You are vulnerable to CSRF attack.
 }
?>

令牌应该很难猜测,对于每个插入请求都是唯一的,只能通过$ _POST接受,并且在几分钟后过期 (本图中未显示有效期。)