Expert Cybersécurité & IAv9.0
Centres de ressources conformité
Besoin d'un accompagnement expert ?
Devis personnalisé sous 24h — audit, conformité, incident
Checklists Sécurité — Audit & Durcissement
Formats disponibles
📄 PDF 📊 Excel 🌐 Web

11 checklists professionnelles couvrant 2 200+ points de contrôle. Téléchargement gratuit, aucune inscription.

6 Chapitre 6 sur 10
10 min de lecture

TCP et la connexion fiable

Comprendre TCP en profondeur : structure du segment, three-way handshake, transfert de données, contrôle de flux, congestion, retransmission et états TCP.

Qu'est-ce que TCP ?

TCP (Transmission Control Protocol) est le protocole de transport le plus utilisé sur Internet. Défini dans la RFC 793 en 1981, il offre un service de communication fiable, ordonné et full-duplex entre deux processus applicatifs.

Les caractéristiques fondamentales de TCP

Caractéristique Description
Fiable Les données perdues sont retransmises automatiquement
Ordonné Les segments sont réordonnés à la réception
Contrôle de flux Le récepteur contrôle le débit de l'émetteur
Contrôle de congestion Adaptation au débit disponible du réseau
Full-duplex Transmission simultanée dans les deux sens
Orienté connexion Établissement explicite avant transfert
Basé sur les octets Flux d'octets, pas de frontières de messages

TCP est utilisé par HTTP/HTTPS, SSH, SMTP, FTP, et tout protocole nécessitant une livraison garantie des données.


Structure du segment TCP

Un segment TCP est composé d'un en-tête de 20 octets minimum suivi des données applicatives.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
├─────────────────────────┬─────────────────────────────────────────┤
│    Port source (16 bits)│      Port destination (16 bits)         │
├─────────────────────────┴─────────────────────────────────────────┤
│                    Numéro de séquence (32 bits)                    │
├───────────────────────────────────────────────────────────────────┤
│                  Numéro d'acquittement (32 bits)                   │
├──────────┬──────────┬─────────────────────────────────────────────┤
│Offset(4) │Réservé(6)│ URG ACK PSH RST SYN FIN │  Fenêtre (16b)   │
├──────────┴──────────┴─────────────────────────┴──────────────────┤
│        Checksum (16 bits)        │    Pointeur urgent (16 bits)    │
├──────────────────────────────────┴──────────────────────────────-─┤
│                   Options (0-40 octets)                            │
├───────────────────────────────────────────────────────────────────┤
│                        Données                                     │
└───────────────────────────────────────────────────────────────────┘

Description des champs clés

Champ Taille Description
Port source 16 bits Port du processus émetteur (0-65535)
Port destination 16 bits Port du processus récepteur
Numéro de séquence 32 bits Position du premier octet de données dans le flux
Numéro d'acquittement 32 bits Prochain octet attendu par le récepteur
Data Offset 4 bits Taille de l'en-tête en mots de 32 bits
Flags 6 bits SYN, ACK, FIN, RST, PSH, URG
Fenêtre (rwnd) 16 bits Espace tampon disponible chez le récepteur
Checksum 16 bits Vérification d'intégrité (en-tête + données)

Les flags TCP

Flag Signification Utilisé lors de
SYN Synchronize — initie une connexion Handshake (étapes 1 et 2)
ACK Acknowledge — confirme la réception Handshake étape 3, puis toujours actif
FIN Finish — demande de fermeture propre Four-way teardown
RST Reset — fermeture immédiate/erreur Port fermé, connexion invalide
PSH Push — envoyer immédiatement à l'application Données urgentes
URG Urgent — pointeur urgent actif Rarement utilisé

Le Three-Way Handshake

Avant tout transfert de données, TCP établit une connexion via le three-way handshake (poignée de main en 3 étapes). Ce processus synchronise les numéros de séquence initiaux (ISN) des deux parties.

Les 3 étapes avec numéros de séquence

Client                                    Serveur
  │                                          │
  │──── [SYN] Seq=X ─────────────────────►  │  Étape 1
  │     "Je veux une connexion"              │  Client choisit ISN=X au hasard
  │                                          │
  │  ◄── [SYN-ACK] Seq=Y, Ack=X+1 ─────────│  Étape 2
  │     "D'accord, mon ISN=Y, j'attends X+1"│  Serveur choisit ISN=Y
  │                                          │
  │──── [ACK] Seq=X+1, Ack=Y+1 ───────────►│  Étape 3
  │     "Confirmé, j'attends Y+1"            │
  │                                          │
  │          [Connexion établie]             │

Exemple concret :

Client → Serveur : [SYN]     Seq=1000
Serveur → Client : [SYN-ACK] Seq=5000, Ack=1001
Client → Serveur : [ACK]     Seq=1001, Ack=5001

Pourquoi 3 étapes et pas 2 ?

Deux étapes suffiraient pour que le client sache que le serveur est prêt. Mais il faut aussi que le serveur sache que le client a reçu son SYN-ACK. Le troisième message (ACK du client) confirme cette bidirectionnalité. C'est le minimum mathématique pour synchroniser les deux ISN de manière fiable.

Observer le handshake avec tcpdump

# Capturer le handshake TCP vers un serveur web
sudo tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' port 80 -n

# Exemple de sortie :
# 14:30:01.001 IP 192.168.1.100.54321 > 93.184.216.34.80: Flags [S], seq 1234567890
# 14:30:01.052 IP 93.184.216.34.80 > 192.168.1.100.54321: Flags [S.], seq 9876543210, ack 1234567891
# 14:30:01.052 IP 192.168.1.100.54321 > 93.184.216.34.80: Flags [.], ack 9876543211

# Flags : [S]=SYN, [.]=ACK, [S.]=SYN-ACK, [F.]=FIN-ACK, [R]=RST

Transfert de données

Numérotation des octets

TCP traite le flux de données comme un flux d'octets numéroté. Chaque octet a un numéro de séquence. Si 500 octets de données sont envoyés dans un segment avec Seq=1001, le prochain segment aura Seq=1501.

Segment 1 : Seq=1001, 500 octets de données → octets 1001-1500
Segment 2 : Seq=1501, 500 octets de données → octets 1501-2000
Segment 3 : Seq=2001, 200 octets de données → octets 2001-2200

Acquittements cumulatifs

L'acquittement TCP est cumulatif : Ack=N signifie "J'ai reçu tous les octets jusqu'à N-1, j'attends l'octet N."

Envoi     : Seq=1001, 500 octets
Réception : ACK=1501  ("j'ai reçu jusqu'à 1500, j'attends 1501")

Envoi     : Seq=1501, 500 octets
Réception : ACK=2001  ("j'ai reçu jusqu'à 2000, j'attends 2001")

MSS — Maximum Segment Size

Le MSS est la taille maximale des données dans un segment TCP (hors en-tête). Il est négocié lors du handshake via les options TCP.

MSS typique sur Ethernet : 1460 octets
(MTU Ethernet 1500 - En-tête IP 20 - En-tête TCP 20 = 1460)

Contrôle de flux — La fenêtre de réception

Le contrôle de flux protège le récepteur d'une inondation de données. Le récepteur annonce dans chaque ACK sa fenêtre de réception (rwnd) : la quantité de données qu'il peut accepter sans saturer son tampon.

Récepteur → Émetteur : ACK, rwnd=8192
Signification : "Tu peux m'envoyer jusqu'à 8192 octets sans ACK"

L'émetteur NE PEUT PAS avoir plus de rwnd octets "en vol" sans ACK.

Fenêtre glissante

Flux de données (chaque bloc = 1 segment) :

[1][2][3][4][5][6][7][8][9]...
     │←──── fenêtre rwnd=4 ────→│
     ↑
     Prochain à envoyer

Après ACK du segment 1 :
   [1][2][3][4][5][6][7][8][9]...
          │←── fenêtre ──→│
          ↑
          La fenêtre "glisse" vers la droite

Si rwnd=0, l'émetteur s'arrête et envoie des sondes (Zero Window Probe) toutes les quelques secondes jusqu'à ce que la fenêtre s'ouvre à nouveau.


Contrôle de congestion

Le contrôle de congestion protège le réseau (pas seulement le récepteur) d'une surcharge. TCP maintient une fenêtre de congestion (cwnd) côté émetteur, indépendante de rwnd.

La quantité réelle de données en vol est limitée par : min(rwnd, cwnd).

Slow Start

Au démarrage d'une connexion, TCP ne connaît pas la capacité du réseau. Il démarre avec une cwnd petite (typiquement 10 MSS avec IW10) et double cwnd à chaque RTT jusqu'à atteindre un seuil (ssthresh).

RTT 1 : cwnd = 10 MSS  → envoie 10 segments
RTT 2 : cwnd = 20 MSS  → envoie 20 segments
RTT 3 : cwnd = 40 MSS  → envoie 40 segments
...jusqu'au ssthresh

AIMD — Additive Increase Multiplicative Decrease

Une fois le ssthresh atteint, TCP passe en mode évitement de congestion :

  • Additive Increase : cwnd augmente de 1 MSS par RTT (progression linéaire)
  • Multiplicative Decrease : en cas de perte détectée, cwnd est divisée par 2
Perte détectée (timeout) :
  ssthresh = cwnd / 2
  cwnd = 1 MSS (redémarre slow start)

Perte détectée (3 ACK dupliqués → fast retransmit) :
  ssthresh = cwnd / 2
  cwnd = ssthresh (fast recovery, sans repartir à 0)

Retransmission

TCP retransmet les segments perdus grâce à deux mécanismes :

Timer RTO (Retransmission Timeout)

Chaque segment envoyé déclenche un timer RTO. Si aucun ACK n'est reçu avant expiration, le segment est retransmis. Le RTO est calculé dynamiquement en fonction du RTT mesuré.

Fast Retransmit

Si l'émetteur reçoit 3 ACK dupliqués (même numéro d'ACK répété 3 fois), il infère qu'un segment est perdu et le retransmet immédiatement, sans attendre le RTO. C'est plus rapide que d'attendre le timer.

# Observer les retransmissions avec ss
ss -tn | head -20

# Observer avec tcpdump (recherche de segments avec flag RST ou retransmissions)
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-rst != 0'

# Statistiques TCP globales (retransmissions, erreurs)
netstat -s | grep -i retrans
# ou
ss -s

The Four-Way Teardown (fermeture propre)

La fermeture d'une connexion TCP nécessite 4 échanges car chaque sens de communication doit être fermé indépendamment.

Client                              Serveur
  │                                    │
  │──── [FIN] Seq=X ─────────────────►│  Client ferme son côté émission
  │                                    │
  │  ◄── [ACK] Ack=X+1 ───────────────│  Serveur confirme
  │                                    │  (le serveur peut encore envoyer des données)
  │                                    │
  │  ◄── [FIN] Seq=Y ─────────────────│  Serveur ferme son côté émission
  │                                    │
  │──── [ACK] Ack=Y+1 ───────────────►│  Client confirme
  │                                    │

L'état TIME_WAIT

Après avoir envoyé le dernier ACK, le client entre en état TIME_WAIT pendant 2 × MSL (Maximum Segment Lifetime, typiquement 60 secondes, soit 2 minutes de TIME_WAIT).

Pourquoi ? Pour s'assurer que :

  1. Le dernier ACK est bien arrivé (sinon le serveur renvoie son FIN)
  2. Les anciens segments en transit dans le réseau expirent et ne perturbent pas une future connexion sur les mêmes ports

Les états TCP (machine d'états)

TCP est une machine d'états. Voici les états principaux :

CLOSED → [SYN envoyé] → SYN_SENT → [SYN-ACK reçu] → ESTABLISHED
                                                            │
CLOSED ← [FIN-ACK reçu] ← TIME_WAIT ← [FIN reçu] ← FIN_WAIT_2
                                                            │
                                          FIN_WAIT_1 ← [FIN envoyé]
État Description
LISTEN Serveur en attente de connexions entrantes
SYN_SENT Client a envoyé SYN, attend SYN-ACK
SYN_RECEIVED Serveur a reçu SYN, a envoyé SYN-ACK
ESTABLISHED Connexion active, transfert de données
FIN_WAIT_1 FIN envoyé, attend ACK
FIN_WAIT_2 ACK reçu, attend FIN du pair
CLOSE_WAIT FIN reçu, l'application doit fermer
CLOSING FIN simultanés des deux côtés
LAST_ACK Dernier ACK attendu avant fermeture
TIME_WAIT Attente 2×MSL avant fermeture définitive
CLOSED Connexion terminée
# Voir tous les états TCP en temps réel
ss -tn

# Compter les connexions par état
ss -tn | awk '{print $1}' | sort | uniq -c | sort -rn

# Voir les connexions ESTABLISHED avec le processus propriétaire
ss -tnp state established

# Voir les sockets en TIME_WAIT (indicateur de charge sur un serveur web)
ss -tn state time-wait | wc -l

# Surveiller en temps réel
watch -n 1 'ss -tn | awk "{print \$1}" | sort | uniq -c'

L'algorithme de Nagle

L'algorithme de Nagle (RFC 896) empêche l'envoi de très petits segments ("tinygrams") en regroupant les petites écritures applicatives. TCP attend que :

  • Il y ait assez de données pour remplir un segment de taille MSS, ou
  • Tous les segments précédemment envoyés ont été acquittés

Cela améliore l'efficacité réseau mais ajoute de la latence. Pour des protocoles interactifs (SSH, gaming), Nagle est souvent désactivé :

# Désactiver Nagle en Python
import socket
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

# Désactiver Nagle avec netcat
nc -N ...

Commandes pratiques complètes

# Observer le trafic TCP sur le port 80
sudo tcpdump -i eth0 tcp port 80 -n

# Afficher toutes les connexions TCP avec processus
ss -tnp

# Tester la connectivité TCP sur un port
nc -zv google.com 443
# Connected to google.com port 443 [tcp/https] succeeded!

# Tester avec timeout
nc -zv -w 3 192.168.1.50 22

# Simuler un client HTTP simple avec netcat
echo -e "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | nc example.com 80

# Afficher les statistiques TCP du kernel
cat /proc/net/tcp

# Voir les connexions TCP en détail (verbose)
ss -tnip

# Surveiller les connexions d'un port spécifique
watch -n 1 'ss -tnp | grep :443'

Récapitulatif

Concept Détail clé
Three-way handshake SYN → SYN-ACK → ACK (synchronise les ISN)
Numéro de séquence Position de l'octet dans le flux, 32 bits
Acquittement cumulatif Ack=N → "j'ai reçu jusqu'à N-1"
Fenêtre rwnd Contrôle de flux côté récepteur
Fenêtre cwnd Contrôle de congestion côté réseau
Slow Start Croissance exponentielle au démarrage
AIMD +1MSS/RTT, /2 sur perte
Four-way teardown FIN → ACK → FIN → ACK
TIME_WAIT 2×MSL après fermeture, évite les anciens segments
Nagle Regroupe les petites écritures (désactiver pour temps réel)

Passez maintenant au chapitre suivant : UDP : la vitesse avant tout — le protocole sans connexion qui privilégie la rapidité à la fiabilité.

Un projet cybersécurité ?

Expert dispo · Réponse 24h

Devis