personal-website/docs/www/register.php

232 lines
7 KiB
PHP

<?php
$COMMONS = $_SERVER['DOCUMENT_ROOT'] . "/../common";
include_once($COMMONS."/header.php");
// Define previous attempt and error variables and set to empty values.
$usernameOld = $passwordOld = $passwordConfOld = "";
$usernameErr = $passwordErr = "";
/**
* Process the information, and if there are no errors, log the user in.
* Returns true on success, false on failure.
*/
function attempt_register($conn, $username, $password, $passwordConf) {
// Access global variables
global $usernameOld;
global $passwordOld;
global $passwordConfOld;
global $usernameErr;
global $passwordErr;
// Check DB connection
if($conn == null){
header($_SERVER["SERVER_PROTOCOL"]." 503 Service Unavailable", true, 503);
include_once($_SERVER["DOCUMENT_ROOT"]."/errors/503.php");
include_once($COMMONS."/footer.php");
die();
}
// Sanitize inputs
$username = sanitize_input($username);
$password = sanitize_input($password);
$passwordConf = sanitize_input($passwordConf);
// Check if both mandatory fields are filled, if not, set appropriate error messages.
if (empty($username))
$usernameErr = "Please enter your username.";
if (empty($password))
$passwordErr = "Please enter your password.";
if($password != $passwordConf)
$passwordErr = "Password and confirmation are different.";
// If either of the fields were empty,
// set old values for prefill and return.
if(!empty($usernameErr) || !empty($passwordErr)) {
$usernameOld = $username;
$passwordOld = $password;
$passwordConfOld = $passwordConf;
return false;
}
// See if a user with this name is already registered
$stmt = $conn->prepare("SELECT 1 FROM users WHERE username = :username;");
$stmt->bindParam(":username", $username);
// Execute the statement
$stmt->execute();
// Fetch the values
$result = $stmt->fetch(PDO::FETCH_ASSOC);
// If the user is already in the database, or is using a forbidden name
// set errors, old values, and return.
if($result || strtolower($username) == "[deleted]" ||
strtolower($username) == "[guest]" ||
strtolower($username) == "zdenek") {
$usernameErr = "This username is not available";
$usernameOld = $username;
$passwordOld = $password;
$passwordConfOld = $passwordConf;
return false;
}
// Hash the password before inserting
$password = password_hash($password, PASSWORD_DEFAULT);
// Insert the user into database and print a success message.
$stmt = $conn->prepare("INSERT INTO users (username, password)
VALUES (:username, :password);");
$stmt->bindParam(":username", $username);
$stmt->bindParam(":password", $password);
// Execute the statement
$stmt->execute();
return true;
}
display_header("Register");
/**
* If user sent the form, process it. This starts a session.
* Either login user and redirect to index or set error message variables.
*/
if (isset($_POST["submit"])) {
// Attempt to register
$registerResult = attempt_register($conn, $_POST["username"],
$_POST["password"], $_POST["password_conf"]);
// If registration was succesful, display message, footer and die.
if($registerResult) {
printf("<article><h2>Registration succesful!</h2>
You can now continue to
<a href=\"http://www.zdenekborovec-dev.cz/login\">Login</a>.
</article>");
include($_SERVER["DOCUMENT_ROOT"]."/../common/footer.php");
die();
}
}
?>
<article>
<form method="post" action="<?php
echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<h2> Register: </h2>
<table class="noborder-table"><tr>
<td><label for="usermame">Username:</label></td>
<td>
<input type="text" name="username" tabindex="1"
autofocus="autofocus" value="<?php echo $usernameOld;?>">
</td>
<td>
<?php echo $usernameErr; ?>
</td>
</tr><tr>
<td><label for="password">Password:</label></td>
<td>
<input type="password" name="password" tabindex="2"
value="<?php echo $passwordOld?>">
</td><td>
<?php echo $passwordErr; ?>
</td>
</tr><tr>
<td><label for="password_conf">Password confirmation:</label></td>
<td>
<input type="password" name="password_conf" tabindex="3"
value="<?php echo $passwordConfOld?>">
</td>
</tr></table>
<input name="submit" type="submit" tabindex="4" value="Send">
</form>
<hr>
<p>
Average time needed to crack a password with 12 RTX 4090 graphics cards
by length (<a href="https://www.hivesystems.com/password">source</a>,
<a href="https://images.squarespace-cdn.com/content/v1/
5ffe234606e5ec7bfc57a7a3/c8c21f1a-ac0a-4dd5-97bf-51a2e4fa63e4/
Hive+Systems+Password+Table+-+2024+Square.png">image</a>):
<table>
<tr>
<td><b>6</b></td>
<td> 12 hours </td>
<td></td>
<td><b>10</b></td>
<td> 33k years </td>
<td></td>
<td><b>14</b></td>
<td> 805bn years </td>
</tr>
<tr>
<td><b>7</b></td>
<td> 1 month </td>
<td></td>
<td><b>11</b></td>
<td> 2m years </td>
<td></td>
<td><b>15</b></td>
<td> 56tn years </td>
</tr>
<tr>
<td><b>8</b></td>
<td> 7 years </td>
<td></td>
<td><b>12</b></td>
<td> 164m years </td>
<td></td>
<td><b>16</b></td>
<td> 3qd years </td>
</tr>
<tr>
<td><b>9</b></td>
<td> 479 years </td>
<td></td>
<td><b>13</b></td>
<td> 11bn years </td>
<td></td>
<td><b>17</b></td>
<td> 276qd years </td>
</tr>
</table>
<p>
Note that these values assume that the attacker has access to a
database of hashed password, and is trying to log into as many
accounts as possible, so not really applicable for someone trying to
get into specifically your account and guessing the passwords,
but I believe it might still be a good wake-up call for people who
believe 6 or 8 characters are a "strong" password.
</p>
<p>
In case you do not read the linked article (which you should!...
if this interests you, that is. The site has a really shitty,
anti-user design, but the info is a good introduction to the topic)
also note that I took those values from the column assuming
combination of capitalised and non-capitalised letters,
numbers and special symbols.
</p>
</p>
<hr>
<p>
I recommend storing your login credentials safely on a piece of paper in a
locked book/drawer, or in an offline (or, if you need syncing, hosted
on-prem), encrypted FOSS password database (I recommend
<a href="https://keepassxc.org/">KeePassXC</a>). I would strongly advise
against reusing the same password and remembering it, or entrusting it
to some tech giant like mozilla, google, lastpass or whoever else
might be trying to convince you to store your passwords in their cloud.
</p>
<p>
Important thing to remember if you are trying to protect against a
<b>directed</b> attack is to keep the length of you password randomized
as well, If I were an attacker, and you revealed to me that you use 12
character password on my site, I am most likely going try that very
password an all the sites where I want to compromise you, and then
prioritize other 12 character passwords. By having your password length
random for each site (in a range you determine as safe, obviously),
you minimize this risk.
</p>
</article>
<?php
include_once($COMMONS."/footer.php");
?>