Sécurisation des BD
Protection des données stockées contre les accès non autorisés et les fuites d'information
Notions théoriques
Les bases de données contiennent des informations sensibles qu'il est essentiel de protéger contre les attaques et les accès non autorisés.
Plusieurs techniques permettent d'améliorer la sécurité des bases de données.
Chiffrement des données
Le chiffrement permet de rendre les données illisibles sans la clé de déchiffrement. Il existe deux types de chiffrement couramment utilisés :
- Chiffrement au niveau des colonnes : Seules certaines colonnes contenant des données sensibles sont chiffrées (exemple : numéros de carte bancaire).
- Chiffrement au niveau du disque ou du fichier : L'ensemble de la base de données est chiffré pour empêcher la lecture des fichiers de stockage.
Les algorithmes les plus utilisés sont AES (Advanced Encryption Standard) et RSA (Rivest-Shamir-Adleman).
Hashage des mots de passe
Les mots de passe ne doivent jamais être stockés en clair. Le hashage permet de transformer un mot de passe en une empreinte unique et irréversible.
- Algorithmes de hashage courants : bcrypt, Argon2, SHA-256.
- Ajout d'un sel : Un sel est une valeur aléatoire ajoutée au mot de passe avant le hashage pour éviter les attaques par dictionnaire.
Contrôle des accès et authentification
Limiter l'accès aux bases de données est essentiel :
- Utilisation de rôles et permissions : Chaque utilisateur doit avoir uniquement les droits nécessaires.
- Authentification forte : Utilisation de méthodes comme l'authentification multi-facteurs (MFA).
- Sécurisation des connexions : Utilisation de TLS/SSL pour chiffrer les communications entre l'application et la base de données.
Prévention des injections SQL
Les injections SQL permettent à un attaquant d'exécuter des commandes malveillantes sur la base de données.
- Utilisation de requêtes préparées : Empêche l'injection de code SQL en séparant les données des commandes SQL.
- Validation des entrées utilisateur : Vérification stricte des données saisies avant de les utiliser dans une requête.
Exemple pratique
Il est possible de sécuriser une base de données MySQL en appliquant plusieurs mesures de protection.
1) Chiffrement des colonnes sensibles
- Se connecter à MySQL :
mysql -u root -p
- Créer une table avec une colonne chiffrée :
CREATE TABLE utilisateurs (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL,
mot_de_passe VARBINARY(255) NOT NULL
);
- Insérer un mot de passe chiffré avec AES :
INSERT INTO utilisateurs (email, mot_de_passe)
VALUES ('user@example.com', AES_ENCRYPT('monMotDePasse', 'cleSecrete'));
- Vérifier que le mot de passe est stocké sous forme chiffrée :
SELECT * FROM utilisateurs;
2) Hashage des mots de passe avec bcrypt en PHP
- Installer la bibliothèque
password_hash
en PHP :
$motDePasse = "monMotDePasse";
$hash = password_hash($motDePasse, PASSWORD_BCRYPT);
echo $hash;
- Vérifier un mot de passe saisi par un utilisateur :
if (password_verify("monMotDePasse", $hash)) {
echo "Mot de passe correct";
} else {
echo "Mot de passe incorrect";
}
3) Protection contre les injections SQL avec des requêtes préparées
- Exemple d'injection SQL dangereuse :
SELECT * FROM utilisateurs WHERE email = 'admin@example.com' OR '1'='1';
- Utilisation d'une requête préparée en PHP pour éviter l'injection :
$stmt = $pdo->prepare("SELECT * FROM utilisateurs WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Ce TP permet d'expérimenter différentes techniques de sécurisation des bases de données, en appliquant le chiffrement, le hashage et la protection contre les injections SQL.
1) Création d'une base de données sécurisée
- Ouvrir un terminal et se connecter à MySQL :
mysql -u root -p
- Créer une base de données nommée
securite_bd
:
CREATE DATABASE securite_bd;
- Utiliser cette base de données :
USE securite_bd;
2) Création d'une table avec un stockage sécurisé des mots de passe
- Créer une table
utilisateurs
avec un stockage sécurisé des mots de passe :
CREATE TABLE utilisateurs (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL UNIQUE,
mot_de_passe VARBINARY(255) NOT NULL
);
La table utilisateurs
est maintenant créée avec trois colonnes :
id
: Un identifiant unique pour chaque utilisateur, généré automatiquement.email
: Un champ pour stocker l'adresse e-mail, avec la contrainteUNIQUE
pour éviter les doublons.mot_de_passe
: Un champ de typeVARBINARY(255)
pour stocker les mots de passe sous forme chiffrée.
L'utilisation de VARBINARY
permet de stocker des données binaires comme des mots de passe chiffrés ou hashés.
3) Chiffrement des mots de passe lors de l'inscription
- Insérer un utilisateur avec un mot de passe chiffré en utilisant AES :
INSERT INTO utilisateurs (email, mot_de_passe)
VALUES ('user@example.com', AES_ENCRYPT('MonMotDePasseSecurise', 'cleSecrete'));
- Vérifier que le mot de passe est bien chiffré :
SELECT * FROM utilisateurs;
La requête INSERT
ajoute un nouvel utilisateur avec un mot de passe chiffré.
La fonction AES_ENCRYPT('MonMotDePasseSecurise', 'cleSecrete')
chiffre le mot de passe en utilisant la clé cleSecrete
.
En consultant la table avec SELECT * FROM utilisateurs;
, on remarque que le mot de passe n'est pas stocké en clair, mais sous forme chiffrée.
4) Récupération et déchiffrement du mot de passe
- Récupérer et déchiffrer le mot de passe d'un utilisateur :
SELECT email, AES_DECRYPT(mot_de_passe, 'cleSecrete') AS mot_de_passe_dechiffre FROM utilisateurs;
La fonction AES_DECRYPT(mot_de_passe, 'cleSecrete')
permet de retrouver le mot de passe en clair en utilisant la même clé de chiffrement.
Cette méthode est utile pour vérifier un mot de passe, mais elle n'est pas recommandée en production. Il est préférable d'utiliser un hashage sécurisé.
5) Implémentation du hashage des mots de passe en PHP
- Créer un fichier
hashage.php
et y insérer le code suivant :
<?php
$motDePasse = "MonMotDePasseSecurise";
$hash = password_hash($motDePasse, PASSWORD_BCRYPT);
echo "Mot de passe hashé : " . $hash;
?>
- Exécuter le fichier avec PHP :
php hashage.php
Le script PHP utilise password_hash()
avec l'algorithme bcrypt
pour générer un hash sécurisé du mot de passe.
Lors de l'exécution, un hash est affiché. Ce hash est unique à chaque exécution car bcrypt
génère un sel aléatoire automatiquement.
6) Vérification d'un mot de passe en PHP
- Modifier le fichier
hashage.php
pour ajouter la vérification du mot de passe :
<?php
$motDePasse = "MonMotDePasseSecurise";
$hash = password_hash($motDePasse, PASSWORD_BCRYPT);
if (password_verify("MonMotDePasseSecurise", $hash)) {
echo "Mot de passe correct";
} else {
echo "Mot de passe incorrect";
}
?>
- Exécuter le fichier :
php hashage.php
La fonction password_verify()
compare le mot de passe en clair avec son hash.
Si le mot de passe est correct, le message "Mot de passe correct" s'affiche. Sinon, "Mot de passe incorrect" apparaît.
Cette méthode est plus sécurisée que le chiffrement réversible car elle ne permet pas de retrouver le mot de passe en clair.
7) Protection contre les injections SQL
- Créer un fichier
protection_sql.php
et y insérer le code suivant :
<?php
$pdo = new PDO("mysql:host=localhost;dbname=securite_bd", "root", "");
// Requête sécurisée avec requête préparée
$email = "user@example.com";
$stmt = $pdo->prepare("SELECT * FROM utilisateurs WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user) {
echo "Utilisateur trouvé : " . $user['email'];
} else {
echo "Utilisateur non trouvé";
}
?>
- Exécuter le fichier :
php protection_sql.php
Le script utilise PDO
et une requête préparée pour éviter les injections SQL.
La valeur de $email
est passée en paramètre sécurisé avec execute([$email])
, empêchant les attaques de type injection SQL.
Si un utilisateur avec cet e-mail existe, il est affiché. Sinon, un message indique qu'il n'est pas trouvé.
8) Tentative d'injection SQL et protection
- Modifier le fichier
protection_sql.php
pour tester une injection SQL :
$email = "admin@example.com' OR '1'='1";
- Exécuter le fichier et observer le résultat.
Si la requête n'était pas protégée, cette injection SQL permettrait de récupérer tous les utilisateurs de la base.
Grâce à l'utilisation de requêtes préparées, l'injection SQL ne fonctionne pas et la requête reste sécurisée.
Cela prouve l'importance de ne jamais concaténer directement des entrées utilisateur dans une requête SQL.