English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

invité
1 / ?
retour aux leçons

Les en-têtes comme sacs

Les frameworks de journalisation HTTP traitent les en-têtes de requête comme un sac de paires clé-valeur. L’API de journalisation expose le sac complet. Les opérateurs activent la journalisation des en-têtes pour le débogage : lorsqu’une requête échoue, les en-têtes racontent l’histoire. Aucune liste de blocage intégrée. Aucun filtrage des identifiants dans la documentation. Tous les en-têtes sur disque.

Les en-têtes d’identifiants dans une requête typique :

- Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... (jeton JWT ou OAuth)

- Cookie: session=abc123; auth=xyz789

- X-API-Key: sk-live-abc123...

- X-Auth-Token: ghp_abc123... (jeton d’accès personnel GitHub)

Ces valeurs authentifient la requête. Une fois écrites dans un fichier journal, elles permettent d’authentifier n’importe quelle requête.

Le pipeline des identifiants

Un identifiant écrit dans un fichier journal ne reste pas à un seul endroit. Il circule :

1. Le serveur web écrit dans /var/log/nginx/access.log

2. L’agent de rotation des journaux (logrotate) copie vers /var/log/nginx/access.log.1

3. L’expéditeur de journaux (Fluentd, Filebeat, Logstash) lit et envoie vers l’agrégateur

4. L’agrégateur de logs (Elasticsearch, Splunk, Datadog) indexe et stocke

5. Conservé pendant 30 à 90 jours selon la politique par défaut

Le credential existe simultanément dans les cinq emplacements. La révocation du jeton de session ne supprime pas le credential de l’agrégateur de logs. Il reste consultable, exportable et accessible à toute personne disposant d’un accès aux logs pendant toute la période de rétention.

La fenêtre d’exposition

Fenêtre d’exposition d’un credential en mémoire : max(durée de session, durée de vie du processus). Session : quelques heures à quelques jours. Processus : quelques heures à quelques semaines.

Fenêtre d’exposition d’un credential dans un log : max(durée de session, durée de rétention des logs). Session : quelques heures à quelques jours. Rétention : 30 à 90 jours.

Un credential volé en mémoire nécessite que l’attaquant soit présent pendant la fenêtre de session. Un credential volé dans un log ne nécessite qu’un accès à l’agrégateur de logs, disponible rétroactivement, pendant toute la période de rétention.

MOAD-0003 vs MOAD-0004

MOAD-0003 (Fuite de contexte) : un identifiant en mémoire fuit vers le mauvais gestionnaire de requête. Accessible uniquement pendant la fenêtre du processus, via le pool de threads. Éphémère.

MOAD-0004 (Secret journalisé) : un identifiant sur disque persiste après la rotation, l’expédition et l’agrégation des journaux. Accessible rétroactivement, à toute personne ayant accès aux journaux, pendant 30 à 90 jours. Persistant.

La différence structurelle : éphémère versus persistant. La correction s’opère à une couche différente.

Éphémère vs Persistant

La distinction éphémère/persistant détermine la surface de risque, la couche de correction et les exigences de réponse aux incidents.

Pourquoi MOAD-0004 présente-t-il un risque plus élevé que MOAD-0003 ? Comparez l’emplacement et la durée de vie de chaque identifiant.

Liste de refus des identifiants au niveau de la couche de sérialisation

La correction : une liste de refus des identifiants au niveau de la couche de sérialisation. Avant qu’une valeur d’en-tête atteigne la sortie du journal, vérifiez le nom de l’en-tête par rapport à une liste de refus. Remplacez la valeur par [REDACTED].

CREDENTIAL_HEADERS = {
'authorization',
'cookie',
'x-api-key',
'x-auth-token',
'x-csrf-token',
'proxy-authorization',
}

def sanitize_headers(headers: dict) -> dict:
return {
k: '[REDACTED]' if k.lower() in CREDENTIAL_HEADERS else v
for k, v in headers.items()
}

La denylist appartient à la couche de sérialisation, pas à la couche de requête de logs. Redaction des requêtes de logs : s’applique après que le credential a atteint le disque ; la valeur brute existe toujours, simplement masquée à l’affichage. Redaction à la couche de sérialisation : le credential n’atteint jamais le disque. La valeur brute n’entre jamais dans le fichier de log, le shipper de logs, ni l’agrégateur de logs.

Test de la Denylist

Trois modèles de test :

- Positif : une requête avec Authorization: Bearer token123 produit une entrée de log avec Authorization: [REDACTED]

- Négatif : une requête avec Content-Type: application/json génère une entrée de journal avec la valeur intacte

- Insensible à la casse : AUTHORIZATION: Bearer token123 produit également [REDACTED] (les noms d'en-têtes HTTP sont insensibles à la casse)

La liste de refus nécessite une maintenance : les nouveaux modèles d'en-têtes d'identifiants (par ex. les en-têtes personnalisés X-Service-Auth) doivent être ajoutés explicitement. Le correctif est structurel mais non auto-maintenu.

Appliquer la liste de refus

Une équipe configure le format de son journal d'accès Nginx pour inclure tous les en-têtes de requête afin de déboguer un incident en production. La configuration :

log_format debug_format '$remote_addr - $request - $http_authorization - $http_cookie';
access_log /var/log/nginx/debug.log debug_format;

Ils résolvent l’incident et prévoient de supprimer la configuration de débogage, mais la modification n’atteint pas la production avant le cycle de déploiement suivant (7 jours plus tard).

Identifiez le défaut. Quels en-têtes d’identifiants pourraient être exposés ? Décrivez l’approche de la liste de refus : où s’applique-t-elle, que vérifie-t-elle et que produit-elle ?