我目前正在学习PHP,并决定编写一个登录和注册系统,以了解错误处理、mysql、密码哈希和基本查询。
我知道有一些标准的身份验证系统具有类似Laravel这样的框架,但我想自己编写一个,只是为了学习。
我想得到一些反馈,基于:
安全当然是主要的事情在这里,如果你有任何其他反馈,请张贴它,因为它是非常感谢!
My注册表单
prepare('INSERT INTO `users` (user_name, user_password, user_email, user_perms, user_created_at) VALUES (?, ?, ?, ?, ?)');
if($stmt) {
// If statement gets sent correctly, create variables and add them
$username = $_POST['username'];
// Hash users' password
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$email = $_POST['email'];
// Timestamp
$date = date('Y-m-d H:i:s');
// Standard user permission level
$perms = "Gebruiker";
// Bind parameters
$stmt->bind_param('sssss', $username, $password, $email, $perms, $date);
// Check whether query ran succesfully or not
if($stmt->execute()) {
$err = "Het account is aangemaakt";
$class = "succes";
} else {
$err = "Deze gebruikersnaam wordt al gebruikt";
$class = "fail";
}
}
}
}
?>
REGISTER
REGISTER
";
echo "" . $err . "";
echo "";
}
?>
Ik heb al een accountMy登录表单
prepare('SELECT user_name, user_password, user_email, user_perms FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
// Send parameters to the server
$stmt->bind_param('s', $username);
// Run statement
$stmt->execute();
// Get query result
$result = $stmt->get_result();
// Fetch the query result in a row and bind to variables
while($row = $result->fetch_assoc()) {
$hash = $row['user_password'];
$username = $row['user_name'];
$email = $row['user_email'];
$userPerms = $row['user_perms'];
}
// If there's no hash, the user does not exists
if(empty($hash)) {
$err = "Sorry, maar deze gebruik bestaat niet";
$class = "fail";
} else {
// Check whether password matches hash on server
if(password_verify($password, $hash)) {
// Hash matches password
session_start();
// Bind session variables
$_SESSION['username'] = $username;
$_SESSION['email'] = $email;
// Login succesful, set message and class accordingly
$err = "Succesvol ingelogt. Redirecting...";
$class = "succes";
// Redirect to secured page
header("Location: admin.php");
} else {
// Password doesn't match hash, set error message accordingly
$err = "Wachtwoord is incorrect";
$class = "fail";
}
}
}
}
}
?>
NNNEXT - INLOGGEN
Inloggen op nnnext.click
";
echo "" . $err . "";
echo "";
}
?>
Ik heb nog geen accountMy身份验证文件
My注销文件
发布于 2018-05-12 22:51:55
我不会进入安全领域(其他人会在这方面做得更好),但是我可以看到一些一般性的问题,或者是一些小问题。
简单干净的代码使许多事情变得更容易。重构、错误发现、维护等。
例如,当您检查某件事情是真的,然后是大量的代码,然后是另一个代码,就很难读懂。尽量尽量保持短小。
例如,您的if ($stmt),而不是检查是否有问题,并提前返回:
if (!$stmt) {
$error = [
'error' => 'We are having problems retrieving results. etc'
];
// Then call or return to your view and tell them about the error
}
// No need for an else, just do the code
// as the above would have returned if there was a problem也就是说,上面的内容应该与声称是登录表单的文件分离。这不是登录表单,即数据库查询和检查查询是否有效。
如果您将文件解耦成不同的部分,则可以重用这些内容。例如,在不同的文件中有多少次连接到数据库,检查连接是否正常,然后执行类似的操作?这可以集中在一个地方,每一个需要使用的地方,都可以称为它设置的一个地方。https://en.wikipedia.org/wiki/Single_责任_原则 https://en.wikipedia.org/wiki/Separation_的_关切
For示例:您的“登录表单”文件应该是从控制器传递数据的表单文件。不是数据库调用和错误检查以及数据检索。
在登录和注册中,包含DB文件并检查一些post数据,如果出现问题,则设置错误和类。他们俩都做同样的事。一个让您思考如何开始将代码解耦以使代码更易于管理的示例:
文件formInputErrors.php (或任何适合的名称):
function formInputErrors(array $formInput = [])
{
foreach ($formInput as $inputValue) {
if (empty($inputValue)) {
return [
'error' => 'Vul alle velden in',
'class' => 'fail',
];
}
}
return null;
}然后,在您的登录名和注册文件中,只需执行以下操作:
include 'formInputErrors.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$formErrors = formInputErrors($_POST);
if ($formErrors !== null) {
// Call or return to your view and tell them about the error
}
}检查是集中的,可以在任何地方重复使用,并且是相同的(没有烦人的复制、粘贴或粘贴失败,也没有相同的检查等等)。如果您想要更改它,例如可能所有字段都不需要是数字,那么您可以在一个地方更改它。
在这一点上,你应该检查的不仅仅是空的。这是一个类有不同的方法的地方(一个用于电子邮件检查,一个用于名称,等等)。但是,您可以将更多的函数放在这个单独的文件中,然后调用您需要的任何一个函数。如function checkEmailAddress()等。
在您的“登录表单”代码中:
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);您实际上已经定义了如何在脚本中哈希密码,这个脚本应该是用于“登录表单”的。如果需要在其他地方散列密码,则必须在那里复制密码,然后在两个位置定义密码。
如果您需要更改散列密码的方式(不太可能,但规则适用于所有方面,不管多么不可能),那么您需要找出您所做的所有位置并对其进行更改。希望你把它们都拿走了,别留下窃听器或者更糟的,一个小小的安全漏洞.
因此,另一个与上面的解耦示例:
在一个单独的文件中:
function hashPassword($passwordToHash)
{
return password_hash($passwordToHash, PASSWORD_DEFAULT);
}然后,您需要知道密码的散列值的任何地方:
$password = hashPassword($_POST['password'];
if ($password === false) {
return [
'error' => 'Something went wrong in our system, try again, contact if persist',
];
// Call or return to your view and tell them about the error
}您使用准备好的语句,这是很棒的,但它不是魔术棒。您不检查用户输入的数据是否“有效”。我可以通过"meh“的电子邮件地址等。
有非标准字符的用户名呢?那么重复的用户名呢?如果字段是唯一的,那么您需要检查它没有被使用,而不是因为重复的插入错误而让MySQL错误退出。
如果您的用户名字段是varchar(25),并且我发送了30个字符,我的用户名可能会被存储,但会被截断,这意味着您允许我用我想要的用户名注册5个字符。也许我没有注意到这一点,然后很难在下一次登录。
你怎么做用户名取决于你的系统允许什么。电子邮件相对简单:
在您的函数文件中进行验证(或任何地方):
function validateEmail($emailToValidate)
{
return filter_var($emailToValidate, FILTER_VALIDATE_EMAIL);
}在你的注册文件中:
if (validateEmail($_POST['email']) === false) {
// Return/call the view and pass in the error
}https://codereview.stackexchange.com/questions/194271
复制相似问题