227 lines
6.8 KiB
PHP
227 lines
6.8 KiB
PHP
<?php
|
|
$COMMONS = $_SERVER['DOCUMENT_ROOT'] . "/../common";
|
|
|
|
include_once($COMMONS."/header.php");
|
|
|
|
display_header("Register");
|
|
|
|
// 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.
|
|
*/
|
|
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){
|
|
printf("
|
|
<article>
|
|
<h1>Failed DB connection, cannot proceed!</h1>
|
|
If you see this error in production,
|
|
please shoot me an email with helpful details.
|
|
</article>");
|
|
include_once($GLOBALS['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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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();
|
|
printf("<article><h2>Registration succesful!</h2>
|
|
You can now continue to
|
|
<a href=\"http://www.zdenekborovec-dev.cz/login\">Login</a>.
|
|
</article>");
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
attempt_register($conn, $_POST["username"], $_POST["password"],
|
|
$_POST["password_conf"]);
|
|
}
|
|
?>
|
|
|
|
<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");
|
|
?>
|