Commit 58448695 authored by Fabrice's avatar Fabrice
Browse files

chiffrement et hachage

parent 867d6da9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

### HTTP
- [Sécurité http](http/Fiche Sécurité http.md)
- [Chiffrement et hachage](http/Fiche Chiffrement et hachage.md)
- [Tokens http](http/Fiche Tokens http.md)

### Tests
+288 −0
Original line number Diff line number Diff line
# Bloc 3 : Chiffrement et hachage dans les protocoles applicatifs

## 1. **Les fonctions en mathématiques**
Une fonction est une relation mathématique qui prend une valeur et lui en associe une autre. On note souvent `f` la fonction et `x` le nombre de départ. On note `f(x)` le nombre d'arrivée.

Une fonction peut avoir plusieurs propriétés (*injective*, *surjective* ou *bijective*) :

![alt text](fichechiff-img/fonctions.png)

### **Fonction**
Une fonction est une relation entre deux ensembles, où chaque élément de l'ensemble d'entrée (ensemble A) est lié à un élément de l'ensemble de sortie (ensemble B), mais l'inverse n'est pas forcément vrai.

Exemple : Dans un **menu de restaurant**, chaque plat choisis (entrée) a un prix spécifique (sortie).
- Ensemble A : Les plats (ex. "Pizza", "Pâtes", "Burger")
- Ensemble B : Les prix (ex. 10€, 15€, 12€)

Ici, chaque plat a un prix, donc il existe une relation entre les plats et les prix. Cependant, plusieurs plats peuvent avoir le même prix (par exemple, une pizza et un burger peuvent coûter le même prix). Cela représente une **fonction**, mais ce n'est pas une injection ni une surjection, car plusieurs entrées (plats) peuvent avoir la même sortie (prix).

### Injection
Une fonction est **injective** si chaque élément de l'ensemble d'entrée est mappé vers un élément unique de l'ensemble de sortie. Aucun élément de l'ensemble de sortie n'est lié à plus d'un élément de l'ensemble d'entrée.

Exemple : Imaginons un **casier dans une salle de sport**. Chaque casier est assigné à un utilisateur spécifique.
- Ensemble A : Les utilisateurs (ex. Alice, Bob, Charlie)
- Ensemble B : Les casiers (ex. C1, C2, C3)

Ici, chaque utilisateur se voit attribuer un casier unique. Si Alice prend le casier C1, aucun autre utilisateur (comme Bob ou Charlie) ne pourra utiliser ce casier. Chaque utilisateur a un casier distinct. Cela montre une **fonction injective**, car un casier est attribué à une seule personne et inversement. Il n'y a pas de chevauchement dans les attributions de casiers. Par contre, un casier peut n'être attribué à personne.

### Surjection
Une fonction est **surjective** si chaque élément de l'ensemble de sortie est couvert par au moins un élément de l'ensemble d'entrée. Cela signifie que tous les éléments de l'ensemble de sortie doivent être atteints par les éléments de l'ensemble d'entrée.

Exemple : Imaginons un **moteur de recherche**. Le moteur de recherche fournit des résultats pour toutes les requêtes que les utilisateurs peuvent faire.
- Ensemble A : Les requêtes des utilisateurs (ex. "météo Paris", "meilleur film 2024", "recette gâteau au chocolat")
- Ensemble B : Les résultats de recherche (ex. sites Web, vidéos, articles)

Si tous les résultats sont couverts par des requêtes (par exemple, chaque article, vidéo ou page Web dans l'ensemble B est l'issue d'une recherche dans l'ensemble A), on parle d'une **fonction surjective**. Tous les résultats possibles sont atteints grâce aux différentes requêtes.

### Bijection
Une fonction est **bijective** si elle est à la fois **injective** et **surjective**. Cela signifie que chaque élément de l'ensemble d'entrée est mappé sur un élément unique de l'ensemble de sortie, et que chaque élément de l'ensemble de sortie est atteint par un élément de l'ensemble d'entrée.

Exemple : Imaginons une **relation entre les prénoms et les numéros de téléphone** d'un petit groupe d'amis.
- Ensemble A : Les prénoms (ex. Alice, Bob, Charlie)
- Ensemble B : Les numéros de téléphone (ex. 0612345678, 0623456789, 0634567890)

Si chaque ami a un numéro de téléphone unique et chaque numéro est attribué à une seule personne (aucun doublon), on parle de **bijection**. Chaque prénom correspond à un numéro unique, et chaque numéro est attribué à une personne unique. Cela respecte les deux conditions : **injective** (chaque prénom a un seul numéro) et **surjective** (chaque numéro est utilisé).

##  2.Chiffrement vs Hachage

|  **Concept**       |  Définition | Objectif |  Exemples | Réversible ? |
|----------------|--------------|------------|------------|----------------|
| **Chiffrement** | Transformation réversible d'un message en un texte illisible via une clé secrète. | Assurer la confidentialité des données. | AES (symétrique), RSA (asymétrique, utilisé pour TLS, emails chiffrés). | ✅ Oui, avec la clé. |
| **Hachage** | Transformation irréversible d’un message en une empreinte unique (hash). | Vérifier l'intégrité des données (détecter une modification). | SHA-256 (certificats SSL), bcrypt (stockage des mots de passe). | ❌ Non, c'est irréversible. |

## 3. Hachage cryptographique
Le **hachage cryptographique (SHA-256, bcrypt)** est basé sur des **fonctions mathématiques non réversibles** qui rendent impossible le retour en arrière.  

- Une **entrée X** produit un **hash Y** tel que :
  ```math
  Y = H(X)
  ```
- Toute modification de X **change complètement** Y (**effet avalanche**).
- Il est **impossible de retrouver X à partir de Y** (la fonction n'est pas *bijective* mais *surjective*).

### **Pourquoi c’est sécurisé ?**  
* **Car on utilise des opérations *complexes*** (rotations, XOR, modulo). Les fonctions de hachage comme SHA-256 utilisent des opérations *bitwise* (*bit à bit* manipulant directement un nombre en effectuant des opérations logiques élémentaires sur chaque bit individuellement). Ces opérations permettent de mélanger les bits de manière difficile à inverser. 


* **SHA-256 applique 64 transformations pour brouiller les données**. SHA-256 est un algorithme de hachage qui transforme un message de n'importe quelle taille en une sortie de 256 bits. Ce processus inclut 64 transformations pendant lesquelles les bits du message sont constamment mélangés. Ces transformations sont réalisées à chaque tour d'une boucle de 64 étapes, et chaque étape utilise des constantes et des résultats intermédiaires pour brouiller les données de façon non linéaire. Cela garantit que même un petit changement dans l'entrée produit une sortie complètement différente (propriété appelée "avalanche"). Ces transformations utilisent des opérations bitwise comme le XOR, les rotations et le modulo que j'ai décrites précédemment pour rendre le processus de hachage difficile à prédire et résistant aux attaques.


* **les fonctions de *hash* comme `bcrypt` ajoutent un "sel" aléatoire** pour empêcher les attaques par rainbow table. Un "sel" (ou salt en anglais) est une donnée aléatoire ajoutée au mot de passe avant qu'il ne soit haché. Cela empêche les attaques par rainbow table, qui sont une méthode pour casser les hachages en pré-calculant des correspondances entre des mots de passe courants et leurs hachages. Le "sel" rend chaque hachage unique, même si deux utilisateurs ont le même mot de passe. Cela complique énormément l'usage des rainbow tables, car il faudrait recalculer les tables pour chaque possible "sel", ce qui est peu pratique.


* **Bcrypt utilise un processus de hachage itératif**, où le mot de passe et le "sel" sont hachés plusieurs fois, ce qui rend l'attaque par brute force beaucoup plus lente et difficile à réussir.


* **Les fonctions de hachage utilisent des facteurs de coût**. Si on ne connait pas le mot de passe et qu'on souhaite tenter une attaque en force brute, le facteur de coût est exponentiel. Par exemple, `bcrypt` utilise un facteur de coût (souvent exprimé par un nombre comme 10, 12, 14, etc.), qui définit combien de fois l'algorithme doit être exécuté. Ce facteur est exponentiel, c'est-à-dire que pour chaque augmentation du facteur, le temps de calcul augmente de façon exponentielle. Par exemple, avec un facteur de coût de 10, bcrypt effectue 2^10 itérations. Avec un facteur de coût de 12, il effectue 2^12 itérations, et ainsi de suite. Cela rend l'attaque par force brute beaucoup plus lente.

  * Pourquoi c'est un problème pour un attaquant : Si un attaquant veut deviner un mot de passe en effectuant une attaque par force brute, il doit calculer un hachage bcrypt pour chaque tentative et vérifier s'il correspond au hachage stocké. Grâce au facteur de coût, chaque tentative prend beaucoup de temps, même avec des processeurs puissants.
      Par exemple, pour un facteur de coût de 12, chaque calcul de hachage pourrait prendre environ 100 millisecondes (selon la puissance du matériel). Donc, même si l'attaquant essaie 1000 mots de passe par seconde, cela prendrait environ 17 minutes pour tester 1000 mots de passe. Si l'attaquant doit tester des millions de mots de passe (avec un dictionnaire standard, cela peut rapidement grimper à plusieurs milliards de mots de passe), cela devient pratiquement impossible à réaliser en un temps raisonnable.
  * Calcul parallèle (attaque avec GPU/ASIC) : En théorie, les attaquants pourraient utiliser des GPU puissants (ou des ASIC spécialisés) pour accélérer le calcul des hachages `bcrypt`, mais ces dispositifs sont également limités par la façon dont bcrypt est conçu pour être coûteux en calcul. De plus, certains systèmes de sécurité sont conçus pour limiter l'impact des attaques par GPU en utilisant des techniques comme l'optimisation des coûts ou des limites de requêtes sur les serveurs.

### Exemples concret de hachage en programmation  

#### 1️⃣ Stockage sécurisé des mots de passe en base de données  
**ERREUR à ne pas faire :**  
🚫 **Stocker un mot de passe en clair**  
```sql
INSERT INTO users (username, password) VALUES ('alice', 'monMotDePasse123');
```
❌ Si la base de données est compromise, tous les mots de passe sont accessibles.

**Bonne pratique : hachage avec bcrypt (Node.js)**  
```javascript
const bcrypt = require('bcrypt');
const saltRounds = 10;
const password = "monMotDePasse123";

bcrypt.hash(password, saltRounds, function(err, hash) {
    console.log("Mot de passe haché :", hash);
});
```
✅ Le mot de passe est haché avant stockage, il est impossible de le retrouver.

**Vérification lors de la connexion :**  
```javascript
bcrypt.compare("monMotDePasse123", hash, function(err, result) {
    if (result) {
        console.log("Mot de passe correct !");
    } else {
        console.log("Mot de passe incorrect !");
    }
});
```

#### 2️⃣ Signature et vérification d’un message

**ERREUR à ne pas faire :**  
🚫 **Faire confiance à un message sans le vérifier**
```python
message_recu = "Transfert de 1000€ approuvé"
# ❌ Un attaquant pourrait avoir modifié le message !
```
❌ Si le message est altéré, il peut induire en erreur.

**Bonne pratique : Utiliser HMAC pour signer un message (Python)**
```python
import hmac
import hashlib

secret_key = b"ma_cle_secrete"
message = b"Transfert de 1000€ approuvé"

signature = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
print("Signature :", signature)

# Vérification du message
message_recu = b"Transfert de 1000€ approuvé"
signature_recue = hmac.new(secret_key, message_recu, hashlib.sha256).hexdigest()

if signature == signature_recue:
    print("Message authentique ✅")
else:
    print("Message modifié ❌")
```
✅ Assure que le message n’a pas été modifié par un tiers.

La clé secrète est un élément fondamental dans des algorithmes comme HMAC. Elle est utilisée pour authentifier un message ou une donnée sans révéler son contenu, garantissant que seul un acteur ayant la clé peut valider l'intégrité du message. La clé secrète est partagée entre les deux parties impliquées dans la communication (par exemple, un client et un serveur). Elle est utilisée pour produire un "hash" ou une signature qui garantit que le message n'a pas été altéré et provient bien de la source attendue. Sans cette clé, il est impossible de générer ou vérifier la signature correctement.

La clé doit être conservée secrète et jamais exposée dans les canaux de communication.
Elle doit être complexe, difficile à deviner ou à brute-forcer (généralement un mélange de caractères aléatoires, de chiffres, etc.). Il est crucial qu'une clé secrète soit longue et aléatoire pour rendre toute tentative de falsification très difficile. La clé secrète est partagée uniquement via un canal sécurisé, comme HTTPS, ou une méthode d'échange de clés telle que Diffie-Hellman si on parle de communication asymétrique.

#### 3️⃣ Génération d’un identifiant unique

**ERREUR à ne pas faire :**  
🚫 **Utiliser un simple compteur numérique**
```python
id_utilisateur = 42  # ❌ Facile à deviner et à falsifier
```
❌ Un attaquant pourrait deviner les ID et usurper des identités.

**Bonne pratique : Hachage pour générer un identifiant unique (Python)**
```python
import hashlib
import uuid

email = "alice@example.com"
user_id = hashlib.sha256(email.encode()).hexdigest()

print("ID utilisateur unique :", user_id)
```
✅ Génère un identifiant unique et difficile à deviner.

## 4. Chiffrement ("cryptage" en mauvaise traduction française)  

Le **chiffrement** est une technique utilisée pour protéger les données contre les accès non autorisés. Il est basé sur des **problèmes mathématiques complexes** comme la **factorisation des grands nombres premiers**.  

#### **🔢 Notions mathématiques associées au chiffrement symétrique et asymétrique**

Le chiffrement repose sur plusieurs concepts mathématiques fondamentaux. Voici les principaux :

| **Concept Mathématique**  | **Lien avec le chiffrement** |
|---------------------------|-----------------------------|
| **Fonctions**             | Un chiffrement est une **fonction** qui transforme un message en texte chiffré. |
| **Injection**             | En général, un bon algorithme de chiffrement produit des résultats uniques pour chaque entrée différente, ce qui correspond à une **injection**. |
| **Bijection**             | Un chiffrement **réversible** (comme AES en mode CBC) est une **bijection** : chaque entrée a une sortie unique et peut être inversée avec la clé. |
| **Grand nombre & arithmétique modulaire** | Les algorithmes asymétriques (comme RSA) reposent sur des nombres premiers très grands et des calculs en **arithmétique modulaire**. |


### **4.1. Chiffrement Symétrique**
 **Principe :** Une seule clé est utilisée pour **chiffrer** et **déchiffrer** les données.  
 **Avantage :** Rapide et efficace pour chiffrer de gros volumes de données.  
 **Inconvénient :** La clé doit être partagée entre les parties communicantes, ce qui pose un problème de sécurité.

#### **Exemple : Algorithme AES**
1. **Alice** veut envoyer un message secret à **Bob**.
2. Ils conviennent d’une **clé secrète partagée** (ex : `clé = "123ABCxyz"`).
3. **Alice chiffre** son message avec AES et la clé secrète.
4. Elle envoie le message chiffré à **Bob**.
5. **Bob déchiffre** avec la même clé et retrouve le message original.

**Cas d’usage :**
- Chiffrement des disques durs (**BitLocker, VeraCrypt**).
- Chiffrement des connexions Wi-Fi (**WPA2**).
- Chiffrement des bases de données.

**Chiffrement AES pour stocker des données sensibles (Node.js)**
```javascript
const crypto = require('crypto');
const key = crypto.randomBytes(32);  // Clé secrète
const iv = crypto.randomBytes(16);   // Vecteur d'initialisation

function encrypt(text) {
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return { encryptedData: encrypted, iv: iv.toString('hex') };
}

const data = encrypt("Données ultra-secrètes");
console.log(data);
```

### **4.2. Chiffrement Asymétrique**
**Principe :** Deux clés sont utilisées :
- Une **clé publique** (pour chiffrer).
- Une **clé privée** (pour déchiffrer).  
  📌 **Avantage :** Pas besoin d’échanger une clé secrète, ce qui améliore la sécurité.  
  📌 **Inconvénient :** Plus lent que le chiffrement symétrique.

#### **Exemple : Algorithme RSA**
1. **Bob** génère une paire de clés :
    - Une **clé publique** (qu’il peut partager).
    - Une **clé privée** (qu’il garde secrète).
2. **Alice** veut envoyer un message secret à Bob.
3. Elle **chiffre** son message avec la **clé publique de Bob**.
4. Elle envoie le message chiffré à Bob.
5. **Bob** déchiffre avec sa **clé privée**.

**Cas d’usage :**
- HTTPS / TLS (navigation sécurisée).
- Signature numérique (authenticité d’un document).
- Échange sécurisé de clés pour le chiffrement symétrique (ex : SSH).

**Exemple : Envoi sécurisé d'un mot de passe via une API (authentification)
📩 **Bonne pratique : Ne jamais envoyer un mot de passe en clair**  
❌ Mauvais :
```http
POST /login
Content-Type: application/json

{
    "username": "alice",
    "password": "monMotDePasse123"
}
```
✅ Meilleur : Utilisation de **HTTPS + token JWT**
```http
POST /login
Content-Type: application/json

{
    "username": "alice",
    "password": "mot_de_passe_haché",
    "2FA_code": "123456"
}
```
Le serveur retourne un **token JWT** qui sera utilisé pour les requêtes suivantes.

### **4.3. Différences entre Symétrique et Asymétrique**

| Critère                | Chiffrement Symétrique  | Chiffrement Asymétrique  |
|------------------------|-------------------------|---------------------------|
| **Clés utilisées**      | 1 clé (partagée)        | 2 clés (publique/privée)  |
| **Vitesse**            | Rapide                  | Plus lent                 |
| **Sécurité**           | Moins sécurisé (clé à partager) | Plus sécurisé (clé privée reste secrète) |
| **Exemples**           | AES, DES, ChaCha20      | RSA, ECC, Diffie-Hellman  |
| **Cas d’usage**        | Chiffrement de données massives (disque dur, VPN) | Signature électronique, HTTPS, échange de clés |


### **4.4. Association des deux : Exemple HTTPS **
1.  **Le chiffrement asymétrique** (RSA) est utilisé pour échanger une clé de session.
2.  **Le chiffrement symétrique** (AES) est utilisé ensuite pour sécuriser la communication.

📌 **Pourquoi ?**
- L’asymétrique est sécurisé mais lent.
- Le symétrique est rapide mais nécessite une clé partagée.  
**Solution : On utilise les deux ensemble !**
+7 −8
Original line number Diff line number Diff line
# Bloc 3 : HTTP - Tokens et Cookies

## 1. Définitions Token et Cookie 
Un **cookie** est un petit fichier stocké dans le navigateur contenant des données utilisées par un site web. Il est envoyé automatiquement au serveur (à chaque requête HTTP).

Un **token** est une chaîne de caractères utilisée pour l'authentification et l'autorisation dans les applications web et API. En fonction des besoins (authentification, protection des formulaires, API sécurisées...), différents tokens peuvent être combinés pour renforcer la sécurité d'une application.

### **Identification vs Authentification vs Autorisation**
## 1. **Identification vs Authentification vs Autorisation**

| **Concept**         | **Question clé**       | **Action**                                       | **Exemple**                                                                 |
|----------------------|------------------------|-------------------------------------------------|----------------------------------------------------------------------------|
@@ -20,8 +15,12 @@ Prenons l'exemple d'une application bancaire :
    - Accéder à vos comptes et transactions (autorisé).
    - Mais vous ne pouvez pas accéder aux comptes d'autres utilisateurs, ni gérer les options administratives (interdit).


## 2. Les cookies

Un **cookie** est un petit fichier stocké dans le navigateur contenant des données utilisées par un site web. Il est envoyé automatiquement au serveur (à chaque requête HTTP).

Un **token** est une chaîne de caractères utilisée pour l'authentification et l'autorisation dans les applications web et API. En fonction des besoins (authentification, protection des formulaires, API sécurisées...), différents tokens peuvent être combinés pour renforcer la sécurité d'une application.

Il existe plusieurs types de cookies
- **Session Cookie** : Expire à la fermeture du navigateur.
- **Persistent Cookie** : Stocké pour une durée définie.
@@ -89,7 +88,7 @@ Un **access token** est un jeton temporaire qui permet à une application (clien
2. Si le token est valide, Google répond avec la liste des calendriers de l'utilisateur.


### **4.4. Refresh Token (Token de rafraîchissement)**
### **4.2. Refresh Token (Token de rafraîchissement)**
Un **refresh token** est utilisé pour obtenir un **nouvel access token** sans nécessiter une nouvelle authentification de l'utilisateur.

#### **Caractéristiques principales** :
+7.9 KiB
Loading image diff...