PHP用户身份验证

PHP用户身份验证,php,authentication,Php,Authentication,我从W3Schools网站上的几本书中自学PHP,并使用了一大堆堆栈溢出的帖子 为了尝试并付诸实践,我正在尝试制作一个小型图像库,它实现了一个用户身份验证系统。用户有一个安全访问权限,它决定了他们是否有读写权限,或者是否可以管理其他用户等等。我只知道登录和添加用户内容 我模仿了我的工作,每个人都有一个唯一的员工ID和8位数的电子邮件ID 我知道这是一个远大的目标,但我只是想知道是否有人可以看一看,并告诉我,如果我的代码是朝着正确的方向?把这样的“现实世界”与书中提供的基本例子放在一起是如此不同。

我从W3Schools网站上的几本书中自学PHP,并使用了一大堆堆栈溢出的帖子

为了尝试并付诸实践,我正在尝试制作一个小型图像库,它实现了一个用户身份验证系统。用户有一个安全访问权限,它决定了他们是否有读写权限,或者是否可以管理其他用户等等。我只知道登录和添加用户内容

我模仿了我的工作,每个人都有一个唯一的员工ID和8位数的电子邮件ID

我知道这是一个远大的目标,但我只是想知道是否有人可以看一看,并告诉我,如果我的代码是朝着正确的方向?把这样的“现实世界”与书中提供的基本例子放在一起是如此不同。如有任何意见和建议,将不胜感激

login.php

<!DOCTYPE html>
<?php       
   // Connect to the database
   include('./helpers/db.php');
   include('./helpers/general.php');

   // Check if the user has submitted their details.
   if ($_SERVER['REQUEST_METHOD'] == 'POST') {
       $loginId = htmlspecialchars(($_POST['userId']));
       $loginPass = htmlspecialchars(sha1($_POST['password']));

       // Check if they've submitted blank details.
       if (!checkLoginId($loginId) || (!checkPassword($_POST['password']))) {
           $errorMsg = "Please enter a valid username or password!";
       }

       else {
       // Select the details we want for the session info.
       $stmt = $dbh->prepare("SELECT firstName, lastName, securityLevel FROM 
                            userDetails WHERE registeredNumber = :loginId 
                            AND password = :loginPass" );
       $stmt->bindParam(':loginId', $loginId);
       $stmt->bindParam(':loginPass', $loginPass);
       $stmt->execute();

            // Make sure the user is found, and that there security level is 1 or more.
            if ($stmt->rowCount() > 0) {
                $userDetails = $stmt->fetch();

                if ($userDetails['securityLevel'] < 1) {
                    $errorMsg = "Insufficient access for this user.";
                }

                else {

                // Start a new session and set up the regularly used info.
                session_start();
                $_SESSION['loggedIn'] = 1;
                $_SESSION['userID'] = $loginId;
                $_SESSION['fname'] = $userDetails['firstName'];
                $_SESSION['lname'] = $userDetails['lastName'];
                $_SESSION['security'] = $userDetails['securityLevel'];
                header("Location: ./browser/");
                }
            }

            else {
                $errorMsg = "Invalid User ID or Password!";
            }
       }
   }
?>

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title></title>
</head>
<style type="text/css">
       body {font-family:sans-serif;}
       .warning {color:red;font-weight:bold;}
       #login {margin-left:auto;margin-right:auto;width:200px;border-style:solid;border-width:1px;padding:20px;}
</style>
<body>
   <!-- Display the login form -->
    <div id="login">
        <form action="login.php" method="POST">
        <?php 
        if (isset($errorMsg)) {
            echo '<span class="warning">'. $errorMsg . '</span>';
        } 
        ?>
        <p><label for="userId">User Name:</label><br />
            <input type="text" maxlength="5" name="userId"
              title="Enter your User ID:">
        </p>
        <p><label for="pasword">Password:</label><br/>
            <input type="password" maxlength="12" name="password"
              title="Enter your password:"/>
        </p>
        <p><input id="submit" type="submit" name="submit" value="Submit"></p>
        </form>
    </div>
</body>
<?php
$hostname = 'localhost';
$dbname = 'dam';
$dbuser = 'root';
$dbpass = '****';

// Try and connect to the database and catch the error if it doesn't work.

try 
{
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $dbuser, $dbpass);
    echo "Connected to Database<br/>";
}

catch (PDOException $e) 
{
    print "Error! " . $e->getMessage() . '<br/>';
    die();
}

?>
<?php

// Checks wether the loginID/Registered Number is valid
function checkLoginId($login) {
if ($login == '' || $login == NULL || (!is_numeric($login))) {
    return 0;
}

else return 1;
}

// Checks whether the password is valid
function checkPassword($password) {
if ($password == '' || $password == NULL) {
    return 0;
}

else return 1;
}

function verifyNewUser($userID, $upass, $fname, $lname, $email) {
$hasErrors = 0;
$errorMsg = array();

if ($userID == '' || $userID == NULL || (!is_numeric($userID)) || (strlen($userID) != 5)) {
    $hasErrors++;
    $errorMsg[] = "User ID is either missing, or does not have 5 digits";
}

if ($upass == '' || $upass == NULL || (strlen($upass) <  6)) {
    $hasErrors++;
    $errorMsg[] = "Password is either missing, or does not meet minimum length of six";
}

if ($fname == '' || $fname == NULL || empty($fname)) {
    $hasErrors++;
    $errorMsg[] = "First name is missing.";
}

if ($lname == '' || $lname == NULL || empty($lname)) {
    $hasErrors++;
    $errorMsg[] = "Last name is missing.";
}

if ($email == '' || $email == NULL || empty($email) || (strlen($email) != 8)) {
    $hasErrors++;
    $errorMsg[] = "Check email id, should be 8 characters.";
}

if ($hasErrors == 0) {
    return 1;

}

else {
    echo "Returning with errors<br/>";
    return $errorMsg;
    } 
}
?>
include ("./helpers/general.php");
include('./helpers/db.php');

session_start();

// If the user isn't logged in, send them away...
if (!(isset($_SESSION['loggedIn']) && $_SESSION['loggedIn'] != '')) {
header("Location: ./login.php");
exit();
}

// Get the users full name so we can politely tell them to rack off if they 
// don't have sufficient access to add users.
$uname = $_SESSION['fname'] . ' ' . $_SESSION['lname'];

// Check if the user has the security clearence to add a new user:
if ($_SESSION['security'] != 4) {
echo "Sorry $uname, only level 4 administrators can manage users.<br/>";
echo '<a href="./browser/">Back to Browser</a>';
exit();
}

// Check if they have submitted the form and validate the input
if ($_SERVER['REQUEST_METHOD'] == 'POST') {

$userID = htmlspecialchars($_POST['registeredNumber']);
$upass = htmlspecialchars($_POST['password']);
$fname = ucfirst(htmlspecialchars($_POST['firstName']));
$lname = ucfirst(htmlspecialchars($_POST['lastName']));
$email = htmlspecialchars($_POST['emailID']);
$secLev = $_POST['securityLevel'];
$creator = $_SESSION['userID'];

$valid = verifyNewUser($userID, $upass, $fname, $lname, $email);

if ($valid == 1) {
    // Encrypt the password
    $upass = sha1($upass);

    // Create the array to feed the SQL statement.
    $data = array($userID, $upass, $fname, $lname, $email, $secLev, date('Y-m-d H:i:s'), $creator);

    $dbh->beginTransaction();
    $stmt = $dbh->prepare("INSERT INTO userDetails VALUES('', ?, ?, ?, ?, ?, ?, ?, ?)");
    $stmt->execute($data);
    $dbh->commit();

    if ($stmt->rowCount() > 0) {
        echo "Success, new user $fname $lname added!<br/>";
        echo "Email ID: $email<br/>";
        echo "Security Level: $secLev<br/>";
    }
}    

else if (isset($valid)) {
    foreach($valid as $error) {
        echo '<span style="color:red;font-weight:bold">' . $error . "<span><br/>";
    }
}
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>Add A New User</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <form action="adduser.php" method="post">
    <table>
        <tr>
            <td><label for="registeredNumber">Registered Number:</label></td>
            <td><input type="text" maxlength="5" name="registeredNumber"/></td>
        </tr>
        <tr>
            <td><label for="password">Password:</label></td>
            <td><input type="password" maxlength="12" name="password"/></td>
        </tr>
        <tr>
            <td><label for="firstName">First Name:</label></td>
            <td><input type="text" maxlength="20" name="firstName"/></td>
        </tr>
        <tr>
            <td><label for="lastName">Last Name:</label></td>
            <td><input type="text" maxlength="20" name="lastName"/></td>
        </tr>
        <tr>
            <td><label for="emailID">Email ID:</label></td>
            <td><input type="text" maxlength="8" name="emailID"/></td>
        </tr>
        <tr>
            <td><label for="securityLevel">Security Level:</label></td>
            <td>
                <select name="securityLevel">
                    <option value="0" selected="selected">0 - No Access</option>
                    <option value="1">1 - Read Access</option>
                    <option value="2">2 - Read/Write Access</option>
                    <option value="3">3 - Read/Write/Delete Access</option>
                    <option value="4">4 - User Administrator</option>
                </select>
            </td>
        </tr>
    </table>
    <input type="submit" name="submit" value="Submit"/>
    </form>
</body>
 </html>
<?php

// Destroy the session and go to the login screen.
session_start();
session_destroy();
header("Location: login.php");
?>


您的方法存在严重的安全问题

最大的问题是将密码存储在数据库中。您不需要将密码存储在数据库中,这是一个可怕的想法,可能会成为有人在法庭上起诉您的理由

有多种加密和散列选项可以让您构建这样的系统,而无需将密码存储在数据库中,使用其中之一是标准过程。任何不这样做的人都会在将来提出问题(谷歌搜索“PSN密码泄漏”)

一个好的选择是PBKDF2

然而,这只是最明显的问题。还有一些事情你做得不够完美,这确实是你需要学习如何正确地去做的,或者你根本不应该去尝试。即使您正在使用PBKDF2,您仍然需要学习如何正确使用它


我建议在尝试编写您自己的身份验证系统之前,现在听一下几乎每一集的安全性

您的方法存在严重的安全问题

最大的问题是将密码存储在数据库中。您不需要将密码存储在数据库中,这是一个可怕的想法,可能会成为有人在法庭上起诉您的理由

有多种加密和散列选项可以让您构建这样的系统,而无需将密码存储在数据库中,使用其中之一是标准过程。任何不这样做的人都会在将来提出问题(谷歌搜索“PSN密码泄漏”)

一个好的选择是PBKDF2

然而,这只是最明显的问题。还有一些事情你做得不够完美,这确实是你需要学习如何正确地去做的,或者你根本不应该去尝试。即使您正在使用PBKDF2,您仍然需要学习如何正确使用它


我建议在尝试编写您自己的身份验证系统之前,现在听一下几乎每一集的安全性

我建议反对W3学校:我建议反对W3学校:谢谢@Abhi一定会看看你提供的链接。干杯。嘿@AbhiBeckert我已经看完了你提到的那篇文章。在将密码存储到数据库之前,我已经确认了密码。即使我要使用PBKDF2方法加密密码,我是否仍然必须将该密码存储在数据库中?或者你只是说永远不要在数据库中存储明文密码?再次感谢!无视我的上述评论,我现在明白了。sha1本身不够强大。它专为大规模输入而设计(如4GB),速度非常快。速度快会使您的密码容易受到暴力攻击,特别是因为大多数用户的密码都很弱(任何长度小于100个字符的密码都可以使用sha1进行暴力攻击)。PBKDF2被设计为配置为在服务器上散列一个密码至少需要十分之一秒(你需要使用配置来找出什么设置会产生这个结果),这使得暴力变得极其困难和昂贵。Thank@Abhi一定会查看你提供的链接。干杯。嘿@AbhiBeckert我已经看完了你提到的那篇文章。在将密码存储到数据库之前,我已经确认了密码。即使我要使用PBKDF2方法加密密码,我是否仍然必须将该密码存储在数据库中?或者你只是说永远不要在数据库中存储明文密码?再次感谢!无视我的上述评论,我现在明白了。sha1本身不够强大。它专为大规模输入而设计(如4GB),速度非常快。速度快会使您的密码容易受到暴力攻击,特别是因为大多数用户的密码都很弱(任何长度小于100个字符的密码都可以使用sha1进行暴力攻击)。PBKDF2被设计为配置为在服务器上散列单个密码至少需要十分之一秒(您需要使用配置来找出哪些设置会产生此结果),这使得暴力非常困难和昂贵。