Outils pour utilisateurs

Outils du site


securite

La sécurité de vos logiciels

Introduction

Je tiens à raconter cette petite anecdote sur la sécurité d'un de mes logiciels. Elle vous permettra de prendre du recul sur ce que vous considérez comme "sécurisé".

Un spécialiste en sécurité freelance (donc dont le métier est la sécurité) fait des audits sécurité de logiciels. Il fait gracieusement l'audit de Logiciels Libres pour se faire un peu de publicité. Il y a quelques années il a pris l'initiative de faire l'audit de mon petit logiciel ZeroBin.

J'ai beau me considérer comme relativement éduqué à la sécurité des systèmes et la sécurité des développements, la faille qu'il a découverte m'a littéralement mis sur le cul. Suivez-moi:

Comment fonctionne ZeroBin

ZeroBin est sommes toutes un logiciel assez simple:

  • Vous entrez un texte dans un formulaire.
  • Une fois le formulaire envoyé vous recevez une URL pour partager le document.
  • ZeroBin vous donne également une URL à appeller pour supprimer le document.

L'URL de suppression est de la forme https://sebsauvage.net/paste/?pasteid=dff3cd9bc2220bc2&deletetoken=7b839a03ffcf1915c64331ada37a74c3b34d9791. Elle contient:

  • pasteid : l'identifiant du document à supprimer.
  • deletetoken : un jeton secret autorisant la suppression du document.

Le document n'est supprimé que si le jeton fourni dans l'URL est identique au jeton stocké côté serveur. Jusque là, c'est simple.

Comparer les jetons

Comment comparer les jetons ? Avec l'une des fonctions les plus élémentaires des langages de programmation: Une simple comparaison de chaînes de caractères.

Et concrètement, comment on compare deux chaînes de caractères ? On compare caractère par caractère, et on s'arrête de comparer dès qu'on trouve un caractère différent. (Inutile de comparer le reste de la chaîne, puisqu'on sait qu'elles sont différentes). Exemple:

Cas Données à comparer
Cas 1 7c839a03ffcf1915c64331ada37a74c3b34d9791
7b839a03ffcf1915c64331ada37a74c3b34d9791
En arrivant sur le second caractère, on voit qu'ils sont différents. On a donc pas besoin de comparer le reste de la chaîne pour savoir que les deux chaînes sont différentes.
Cas 2 7b839a03ffcf1915c67331ada37a74c3b34d9791
7b839a03ffcf1915c64331ada37a74c3b34d9791
Là, il a fallu comparer 19 caractères (presque la moitié de la chaîne) avant de tomber sur un caractère différent.
Cas 3 7b839a03ffcf1915c64331ada37a74c3b34d9731
7b839a03ffcf1915c64331ada37a74c3b34d9791
Là, il a fallu comparer presque tous les caractères avant d'en trouver un différent. Il a fallu comparer plus de caractères, ce qui se traduit par un temps d'exécution plus long.

Donc les fonctions de comparaison de chaînes de caractères n'ont pas toujours exactement le même temps d'exécution en fonction des données en entrée. Si les premiers caractères sont différents (cas 1), la fonction se terminera rapidement. Plus les deux chaînes sont identiques sur le début, plus la fonction mettra de temps à s'exécuter (cas 3).

Vous voyez arriver le problème ?

La faille

Le spécialiste en sécurité a donc essayé de supprimer un document sur ZeroBin sans connaître le jeton de suppression (deletetoken). Vue la taille du jeton, essayer à l'aveugle toutes les possibilités serait bien trop long (Il y a 2^160 possibilités, soit 1461501637330902918203684832716283019655932542976 possibilités).

Il a procédé autrement: Il a envoyé un grand nombre de requêtes de suppression avec des tokens aléatoires et a mesuré le temps de réponse du serveur.

Par essais successifs, il sait que plus le serveur met de temps à répondre, plus il est proche de la bonne valeur (puisque la fonction de comparaison de chaînes aura mis plus de temps à s'exécuter). Oh la différence de temps de traitement est infime, mais elle existe.

Il a donc sélectionné progressivement les débuts de jeton qui statistiquement ont donné les temps de réponse les plus longs, et de proche en proche a fini par trouver la bonne valeur du jeton. Il a donc réussi à agir sur un système de données de manière non autorisée (supprimer un document) juste en mesurant les temps de réponse du serveur.

Je vais le redire autrement pour marquer les esprits:

Il a contourné la sécurité d'un système en s'attaquant à une fonction de base des langages: La comparaison de deux chaînes de caractères.

Rappelez-moi à combien de bibliothèques fait appel votre logiciel ?

La solution

La solution est techniquement très simple: Une fonction de comparaison de chaîne à temps constant: Elle compare tous les caractères et ne s'arrête qu'à la fin de la chaîne. En php, cela donne quelque chose du genre:

function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0;
}

(On peut aussi utiliser la fonction hash_equals().)

Bien sûr il existe d'autres solutions comme celle adoptée par NextCloud: Plus le nombre d'essais infructueux augmente, plus l'API met de temps à répondre (ce qui rend aussi ce genre d'attaque inexploitable), ou encore fail2ban (un trop grand nombre d'échecs dans un court lapse de temps provoque une reconfiguration du firewall pour bloquer l'adresse IP émettrice des requêtes).

Conclusions

Cette expérience m'a appris plusieurs choses:

  • Si la sécurité d'un système informatique a pu être attaquée via une fonction de comparaison de chaînes de caractères, alors tout est piratable. (Quelqu'un qui vous dit que son système ne peut pas être piraté ment, soit en connaissance de cause, soit par ignorance, soit par orgueil.)
  • La sécurité, c'est un vrai métier. (Comme dit, j'ai beau être éduqué à la sécurité jamais je n'aurais imaginé cette faille.)
  • Mathématiquement:
    • Plus vous augmentez les dépendances de votre logiciel, plus vous augmentez les risques de sécurité.
      • Ce n'est pas parce qu'une bibliothèque que vous utilisez est très connue que vous êtes à l'abri (exemple: log4j)
    • Plus vous augmentez la complexité de votre logiciel, plus vous augmentez les risques aussi.
    • La simplicité est une vertu pour la sécurité (et pas que pour la maintenance ou les performances), mais elle ne suffit pas.
    • Optimiser est utile, mais peut compromettre la sécurité.
  • Liens sur le sujet :
securite.txt · Dernière modification : 2024/05/30 11:02 de sebsauvage