Avertissement : Cet article a été traduit de l’anglais par un LLM. La précision n’est pas garantie. Vous pouvez lire l’article original en anglais.
Comme j’ai récemment déposé mon premier CVE (CVE-2023-22481 - Divulgation d’informations sensibles dans les fichiers de log de FreshRSS), je voulais profiter de l’occasion pour écrire quelques mots sur ce que j’ai trouvé, quels problèmes la journalisation excessive a pu causer dans ce cas, et quelles sont certaines des bonnes pratiques de journalisation.
Ce que j’ai trouvé#
J’ai récemment commencé à utiliser FreshRSS (excellent logiciel, je le recommande vivement) et j’ai décidé d’installer une application mobile pour pouvoir tout lire depuis mon téléphone. Après avoir installé l’application, j’ai essayé de me connecter avec mon nom d’utilisateur et mon mot de passe, mais l’accès a été refusé. Il se trouvait que j’avais une console SSH ouverte sur mon serveur, alors j’ai suivi les logs et j’ai découvert ce qui suit :
[_POST] => Array
(
[Email] => MyUserName
[Passwd] => MyPassword
)
[_COOKIE] => Array
(
)
[INPUT] => Email=MyUserName&Passwd=MyPassword“Attendez,” ai-je pensé. “On dirait bien mon mot de passe là-dedans.” J’ai ensuite téléchargé le code source et regardé ce qui se passait lors de l’utilisation de l’API. Le snippet suivant est ce que j’ai trouvé :
if user exists:
if user configuration is missing:
log the error and dump the request's headers, get, post, and cookie values
if password is correct:
accept login
else if password is incorrect:
log the error and dump the request's headers, get, post, and cookie values
else if user does not exist:
log the error and dump the request's headers, get, post, and cookie valuesEn gros, si l’authentification échouait, toutes les données de la requête HTTP de connexion étaient journalisées dans le fichier de log du logiciel et dans syslog.
Notez que le pseudo-code dit mot de passe, mais ce qui était attendu était une clé API (le mot de passe utilisateur ne peut être utilisé qu’avec l’interface web).
Quel pourrait être l’impact ?#
Si le logiciel fonctionnait en production avec plusieurs utilisateurs, les situations suivantes auraient pu se produire :
- Un utilisateur entre un mauvais nom d’utilisateur et une mauvaise clé API
- Un utilisateur entre accidentellement un nom d’utilisateur et un mot de passe qu’il utilise pour un autre service
- Un utilisateur entre son nom d’utilisateur et le mot de passe de son compte (au lieu de la clé API attendue)
- Un utilisateur entre un nom d’utilisateur et une clé API valides, mais pour une raison quelconque, son fichier de configuration ne peut pas être lu lorsqu’il essaie de se connecter
Si un utilisateur malveillant exploitait ensuite un bug permettant de lire le fichier de log (notez que syslog est accessible à tous les utilisateurs par défaut), il pourrait faire ce qui suit :
- Utiliser le mot de passe pour se connecter au logiciel en tant que l’utilisateur (les données privées de l’utilisateur sont compromises ; cela donne plus de surface d’attaque)
- Utiliser le login et le mot de passe pour faire du credential stuffing et potentiellement accéder à d’autres comptes appartenant à l’utilisateur
Bonnes pratiques de journalisation (en bref)#
La journalisation est quelque chose que vous voulez avoir dans vos systèmes. Non seulement elle peut vous aider à résoudre les problèmes rencontrés par les systèmes/utilisateurs, mais elle peut aussi aider à investiguer les incidents de sécurité.
Cependant, trop de journalisation peut aussi être un problème. Des logs trop détaillés peuvent introduire divers risques, tant en matière de sécurité (comme nous l’avons vu dans l’exemple précédent) que juridiques.
En règle générale, vous ne devriez jamais journaliser des données telles que les mots de passe, les clés API, les données personnelles (par exemple les données de santé, les numéros de carte de crédit, les numéros de pièces d’identité officielles), les données d’une classification de sécurité supérieure à ce que le système de journalisation est autorisé à stocker, … Ce que vous pouvez (ou devriez) journaliser dépend aussi des réglementations et standards auxquels vous êtes soumis (par exemple le RGPD, PCI DSS, HIPAA).
Bien que vous deviez éviter de journaliser trop de données d’événements (par exemple le contenu complet des requêtes HTTP), vous devez quand même journaliser tous les événements pertinents pour votre système. Par exemple (mais sans s’y limiter) :
- Échec de validation des données
- Authentification des utilisateurs (échec et succès)
- Échecs d’autorisation
- Changement d’état du système (démarrage, arrêt de l’application, …)
- Accès aux données sensibles et modification de données
- Utilisation d’accès privilégiés (ajout de nouveaux utilisateurs, changement de mots de passe, …)
- Erreurs et défaillances de l’application et du système
- Export de données
Lorsque vous journalisez de telles choses, vous voulez répondre aux questions “Qui ? Quand ? Où ? Quoi ?”. Vous pourriez aussi vouloir inclure des informations supplémentaires selon ce que vous journalisez (par exemple, une exception Java si un programme échoue).
Un exemple de logs pour notre situation précédente pourrait être [IP] [Date] Authentification échouée pour l'utilisateur [username] : mauvais mot de passe
En résumé, vous voulez vous demander : “Si un incident se produit, mes logs sont-ils suffisants pour me permettre de trouver la cause et comprendre ce qui s’est passé juste en les consultant ?”
Conclusion#
La journalisation est un vaste sujet, et un article de blog ne suffirait pas pour dire tout ce qu’il y a à dire, mais si vous voulez en savoir plus sur la journalisation, l’OWASP a une très bonne et détaillée fiche pratique. Le livre Practical Monitoring que j’ai mentionné ici est aussi une excellente ressource.
Quelques points qui méritent d’être mentionnés également lorsqu’on parle de journalisation sont le coût financier de la journalisation excessive de données et le risque de journaliser des données non assainies (log4j).
Crédits#
- Photo de couverture par Jake Walker sur Unsplash