17. Login
Within our sites we may need to have a separate page that is only accessible with a password. A place where only the user can enter and that displays sensitive information:
- Settings.
- Profile.
- Bank details.
- Chat conversations.
- History.
- ...
Any element that is unique and private to the visitor.
The strategy that has always been used from the backend is through sessions. When you enter a username/password, a unique key will be created that will let our visitor in, and only them! If they want to leave, they will have a button to break the session, making it impossible for anyone to enter with the machine. Unless they identify themselves again, of course; it is not good to condemn the user to permanent oblivion.
For the example we will need 3 pages: login.php (where we identify ourselves), privado.php (where we enter) and cerrar-sesion.php (code that destroys access).
Encrypting our password
We are talking about the form where we can enter our username and password. In the example I will use an email instead of the name.
If the data is incorrect, it will display a warning message.
You must never reveal whether the user got the email or the password wrong. You would reveal to a potential attacker that one of the 2 pieces of data is correct. Instead, give more generic information: "The email or password is invalid", "Your login details are not correct", etc...
Passwords, for security reasons, must be encrypted in the database. To do this, one of the recommended methods is the following.
// The password is '123'
echo password_hash('123', PASSWORD_DEFAULT);
// $2y$10$OuIiaiZMrVb5nAzrBU4U8eBjCB/rMPEAnNlmM8krh0nZ5Fru/nO7q
If you run the code you will find, to your surprise, that it is different from mine. Even if you run it again... it will be different from the previous one!
Login
The result varies every time. How on earth can you check such a seemingly random system? With the magic of cryptography.
password_verify('123', '$2y$10$OuIiaiZMrVb5nAzrBU4U8eBjCB/rMPEAnNlmM8krh0nZ5Fru/nO7q')
// True
Now let's see everything put together and orchestrated. If you want to review sessions you can go back to chapter 11 Sessions.
We will call the file login.php.
<html>
<body>
<?php
// We check that the form data reaches us
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Fictitious database that will be used in the example.
$baseDeDatos = [
'email' => 'correo@falso.com',
'password' => password_hash('123', PASSWORD_DEFAULT)
];
// Form variables
$emailFormulario = isset($_REQUEST['email']) ? $_REQUEST['email'] : null;
$contrasenyaFormulario = isset($_REQUEST['contrasenya']) ? $_REQUEST['contrasenya'] : null;
// We check if the data is correct
if ($baseDeDatos['email'] == $emailFormulario && password_verify($contrasenyaFormulario, $baseDeDatos['password'])) {
// If it is correct, we create the session
session_start();
$_SESSION['email'] = $_REQUEST['email'];
// We redirect to the secure page
header('Location: privado.php');
die();
} else {
// If it is not correct, we inform the user
echo '<p style="color: red">The email or password is incorrect.</p>';
}
}
?>
<form method="post">
<p>
<input type="text" name="email" placeholder="Email">
</p>
<p>
<input type="password" name="contrasenya" placeholder="Password">
</p>
<p>
<input type="submit" value="Log in">
</p>
</form>
</body>
</html>
Private area
We check whether the session exists; otherwise we automatically send the user back to login.php.
We will call the file privado.php.
<?php
// Enable sessions
session_start();
// Check if the 'email' session exists; otherwise go back to the login page
if (!isset($_SESSION['email'])) header('Location: login.php');
?>
<html>
<body>
<p>
You are in a secret area! Only visible to an identified person.
</p>
<p>
<a href="cerrar-sesion.php">Log out</a>
</p>
</body>
</html>
```
### Log out
Nothing new. We destroy the sessions and redirect to **login.php**.
We will call the file **cerrar-sesion.php**.
``` php
<?php
// Start the sessions
session_start();
// Destroy any user session
session_destroy();
// Redirect to login.php
header('Location: login.php');
```
### Password recovery
The worst thing that can happen is that a **user loses a password**, both for them and for the programmer who built the site. To recover it we will have to follow some well studied steps.
1. **Check that the user is legitimate** and not an opportunist by means of a **secure link**.
2. Since the passwords are encrypted, as we saw earlier, it will not be possible to show it. There will be no choice but to **ask for a new password**.
3. **Overwrite the previous password** with the new one.
4. **Scold the user**. It can be done subtly with a text that suggests keeping it in a safe place.
5. **Take them to the identification page** (`login.php`).
The strategy can be through a reliable verification system. Such as an SMS, an email, a notification, a message via chat... hence the importance of providing real data.
#### How can I create a secure link?
We will send a link via an email with a random number that we will save and that will help us find out whether the user is the same one requesting the new password. Otherwise we ignore it.
For example, a link with the following structure:
``` txt
recuperar_contrasenya.php?verificar=123456789
I will save the value of verificar to compare later.
A secure way to generate the number is by means of openssl.
echo bin2hex(random_bytes(16));
// 60727b7a5f11688aad3662bbd62e065a
Whenever we run it, it will provide us with an alphanumeric string that is fantastically hard to predict.
Our code would look like this.
$tokenSeguro = bin2hex(random_bytes(16));
// Our message in HTML
$mensaje = "
<html>
<head>
<title>Recover your password</title>
</head>
<body>
<a href=\"ejemplo.com?token=$tokenSeguro\">Click here to change it</a>
</body>
</html>
";
// Defines the type of our message: HTML. And the sender's address.
$headers = [
'MIME-Version' => '1.0',
'Content-type' => 'text/html; charset=utf-8',
'From' => 'curso@php.com'
];
// We send it
mail('correo@falso.com', 'Recover your password', $mensaje, $headers);
Now we only need to check that the token we saved is the same and continue with the previous steps.
Activity 1
You have been promoted to a government official and now they ask you to build a platform so that secret agents can find out the names of their colleagues and not eliminate them by mistake.
- Create a login page: email and password.
- If the entered data is correct, redirect to a secure page. This page will have the names of the government's secret agents and a text field to add new ones. This information will come from the database.
- If the data is wrong, the user will be notified.
- Provide the option to log out.
Pro:
- Grant the ability to change the password.
Activity 2
You must build a manager to publish cooking recipes. At a minimum it must have:
- Login.
- Registration.
- Password recovery.
- Database.
- Recipe CRUD.
- Category CRUD.
- Comment CRUD.
Activity 3
- Create several fields to upload images.
- Display the result in a vertical Grid.
Activity 4
- Create a page where you can register: username (nickname), password and email.
- Create a page where you can identify yourself.
- Create a private page with all your messages.
- Provide the option for users to publish new ones.
- Create a button to log out.
This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.
Desafíos de programación atemporales y multiparadigmáticos
Te encuentras ante un librillo de actividades, divididas en 2 niveles de dificultad. Te enfrentarás a los casos más comunes que te puedes encontrar en pruebas técnicas o aprender conceptos elementales de programación.
Buy the bookWill you buy me a coffee?
This is how I keep writing without ads or paywalls.
Sure, it's on me!
Comments
There are no comments yet.