La sécurité dans le développement

Posté par  . Édité par Benoît Sibaud, Al, Bruno Michel, Nÿco, Pierre Jarillon, baud123, freem, Benoît et maboiteaspam. Modéré par Nÿco. Licence CC By‑SA.
21
19
avr.
2013
Technologie

Voici une dépêche qui regroupe quelques bonnes pratiques sur les mots de passe et la gestion des données dans une application. Elle est loin d'être exhaustive et, donc, n'hésitez pas à la compléter dans les commentaires ou d'écrire la suite dans l'espace de rédaction collaborative.

Sommaire

Les mots de passe

Stockage des mots de passe sur le serveur

La principale préoccupation est de limiter les dégâts qui pourraient être causés si un attaquant (ou un admin malveillant) parvenait à lire la base de données de mots de passe. Pour cela, il faut ne surtout pas stocker les mots de passe en clair, mais les transformer en utilisant une fonction de hachage cryptographique préalablement à l'enregistrement. Également connues sous le nom de « fonctions à sens unique », ces fonctions sont faites pour qu'il soit difficile de retrouver leur entrée (le mot de passe en clair) à partir de leur sortie (le mot de passe haché). Contrairement aux fonctions de chiffrement, les fonctions de hachage ne sont pas paramétrées par une clé secrète et ne sont pas bijectives. Grâce à cela, les données stockées permettent uniquement de vérifier facilement qu'un mot de passe entré par l'utilisateur est le bon, mais pas de le retrouver.

Comme il est possible par bruteforce (ou des techniques plus raffinées) de retrouver le mot de passe en clair et qu'il existe des tables précalculées (Rainbow table) pour les principaux algorithmes, il est aussi conseillé de saler les mots de passe. Cela consiste à ajouter des bits aléatoirement générés à la création du login et les ajouter au mot de passe avant d'utiliser la fonction de hachage; cela rend l'utilisation des tables précalculées inutile et l'aspect unique par utilisateur permet d'éviter que deux utilisateurs avec le même mot de passe aient le même résultat de la fonction de hachage.

Avec la puissance de plus en plus importante des ordinateurs, même des hashs (résultat d'une fonction de hachage) salés peuvent permettre de retrouver rapidement les mots de passe les plus courts. Il ne faut donc pas utiliser une fonction de hachage prévue pour traiter rapidement de grandes quantités de données (MD5, SHA-512…) mais des algorithmes prévus pour être lents (bcrypt…). L'intérêt est de ralentir le déchiffrage de votre base de données, et, à moins que vous n'authentifiez des milliers d'utilisateurs par seconde (ce qui peut arriver en cas d'attaque DDoS, il est donc bon de s'en protéger), ça ne devrait pas poser de problème de performances sur votre serveur.

Du côté client

Il faut éviter de stocker des mots de passe en clair sur les postes des utilisateurs, cela permettrait à un intrus ou à un virus de les lire. On peut soit les demander à l'utilisateur au démarrage de l'application ou, s'il y en a plusieurs, les conserver chiffrés avec une clef basée sur un mot de passe demandé à l'utilisateur ou en se basant sur un gestionnaire de mots de passe du système tel que KWallet ou Gnome-keyring.

Données

Données « externes »

Les données externes concernent bien sûr les saisies de l'opérateur, mais également celles provenant des autres programmes, du réseau, de variables d'environnement…
En fait, toute donnée qui a eu une relation avec un autre binaire (les périphériques matériels, donc l'utilisateur, sont après tout perçus au travers des pilotes, qui sont des binaires…) doit être considérée comme externe.

Les bibliothèques sont idéalement à inclure (mais cela représente certainement trop de travail pour être réellement fait) : un simple changement de version peut amener un changement de comportement, qui peut invalider les données et ainsi causer des vulnérabilités. Ce changement de comportement n'impliquant pas nécessairement une rupture de l'ABI (_application binary interface_), on ne peut se fier au système d'exploitation.

Mais le plus probable est une version compromise d'une des dépendances: il suffit qu'un attaquant ait indiqué au système qu'il faut utiliser une version qu'il a lui-même altérée de la bibliothèque (changement du PATH ou LDPATH, en fonction du système d'exploitation attaqué).

Ces données doivent être systématiquement vérifiées et protégées, car elles sont un important vecteur d'attaque. Quelques exemples:

  • buffer overflow : insertion de plus de données que le programme ne l'avait prévu, afin de modifier le binaire lors de son exécution. L'usage de conteneurs dynamiques (listes chaînées, par exemple) permet de réduire drastiquement les risques de ce genre d'attaques, mais impliquent un coût en ressources (temps processeur et occupation mémoire notamment) plus élevé. Ces conteneurs ne sont donc pas la panacée.
  • injection de code : lors de l'usage d'un langage de script (SQL ou PHP par exemple) il est possible d'insérer le caractère permettant de signaler à l'interpréteur la fin d'une chaîne de caractère, puis d'insérer du code directement. Cette attaque est très simple à réaliser.

Données « internes »

Les autres données nécessitent aussi des vérifications, sauf si elles garantissent leur réussite ou si leur état reste valide malgré l'échec d'une opération sur elles (un article intéressant à ce sujet).

Lorsque ces garanties ne sont pas présentes, il faut systématiquement vérifier que tout s'est déroulé comme prévu ou que la donnée est toujours dans un état valide.

Un exemple d'échec pourrait être un élément qui n'est pas correctement initialisé par manque de mémoire, laissant l'objet qui le nécessite dans un état indéterminé.

Ne pas effectuer ces vérifications expose à un risque de plantage, et qui dit risque de plantage dit possibilité d'attaque.

Aller plus loin

  • # Mot de passe côté serveur

    Posté par  (site web personnel) . Évalué à 8.

    À noter que, pour pouvoir ne stocker qu'un hachage du mot de passe sur un serveur, il faut que ce mot de passe soit transmis en clair au code de vérification lors des tentatives d'identification. Ce problème peut être résolu de deux façons :

    • une bonne : sécuriser l'étape d'identification avec une couche de chiffrement comme TLS ;
    • une mauvaise : passer à un système d'identification par défi-réponse, qui implique… de stocker le mot de passe en clair sur le serveur !

    À noter qu'au moins un protocole, SIP, interdit « pour raisons de sécurité » les identifications par mot de passe simple, et propose à la place, toujours « pour raisons de sécurité » une identification par défi-réponse…

    • [^] # Re: Mot de passe côté serveur

      Posté par  (site web personnel) . Évalué à 9.

      Je prends les devants avant qu'on ne me réplique qu'avec l'identification Digest de SIP, le mot de passe n'est pas stocké en clair : c'est techniquement exact mais ce qui est stocké, qui est un hachage du mot de passe et d'une information de domaine, est suffisant pour s'identifier, et constitue donc le mot de passe réel.

    • [^] # Re: Mot de passe côté serveur

      Posté par  . Évalué à 2.

      http://www.wolfe.id.au/2012/10/20/what-is-hmac-and-why-is-it-useful/

      donc non, pas besoin de transferer un mot de passe en clair, ou d'équivalent au mot de passe.
      Suffit d'utiliser une technologie adéquate.

    • [^] # Re: Mot de passe côté serveur

      Posté par  . Évalué à 1.

      Ce problème peut être résolu de deux façons

      Ou de bien d'autres.
      L'une d'entre elles est bien le défi-réponse, sans stocker quoi que ce soit en clair :
      Condition de départ : le serveur stocke le mot de passe haché avec ou sans sel. À noter que le sel est forcément stocké localement en clair. Avec cette méthode il sera également transmis en clair (ou à l'intérieur d'une liaison TLS, donc en clair si attaque MITM)
      1 - le client fait une demande de connexion en indiquant le nom de connexion
      2 - le serveur génère un bloc de données aléatoires, par exemple 1 ko de données, et l'envoie au client. Si sel, il doit être transmis avec le bloc
      3 - l'utilisateur tape le mot de passe
      4 - le client chiffre le bloc aléatoire avec le mot de passe haché (+ sel éventuel) au moyen d'un algo non réversible
      5 - le client génère un sel aléatoire temporaire. Le bloc est re-chiffré avec le mot de passe haché (+ sel éventuel) + le sel temporaire qui vient d'être généré
      6 - le client retourne le bloc résultant au serveur + le sel temporaire
      7 - le serveur chiffre le bloc d'origine avec le hachage local du mot de passe (+ sel éventuel), le re-chiffre avec le mot de passe + sel éventuel + sel temporaire transmis par le client
      8 - le bloc chiffré 2 fois localement doit être le même que celui envoyé par le client

      L'étape 5 sert à limiter les possibilités d'Eve (écoute) qui compare les blocs dans les deux sens. Elle limite également les possibilités de Mallory (modifie/génère des blocs) qui construit des blocs spécifiques pour faciliter le recherche du hachage d'origine.

      Idéalement il faut que le bloc d'origine intègre des données chiffrées (par le hachage+sel éventuel) que le client pourra ainsi déchiffrer. Par exemple un horodatage + bourrage (le bourrage étant en principe le bloc complet, qui se trouve donc chiffré intégralement). Le client sait déchiffrer cela, et sait alors vérifier que le bloc vient d'être généré. Cela limite beaucoup le rejeu.

      • [^] # Re: Mot de passe côté serveur

        Posté par  . Évalué à 7.

        Cela reviens au même: Tu remplace juste le mot de passe par un mot de passe haché, mais qui reste stocké en clair et dont la connaissance est suffisante pour s'authentifier.

        C'est (presque) pareil que l'authentification Digest de HTTP.

        • [^] # Re: Mot de passe côté serveur

          Posté par  . Évalué à 1.

          Tu remplace juste le mot de passe par un mot de passe haché, mais qui reste stocké en clair et dont la connaissance est suffisante pour s'authentifier.

          Cela répond au problème de faire transiter le mot de passe en clair, ce qui est la question de ce fil.

          La seule autre méthode connue est le principe de clef asymétrique. Mais on est loin des mots de passe pour le commun des utilisateurs.

          • [^] # Re: Mot de passe côté serveur

            Posté par  (site web personnel) . Évalué à 5.

            Cela répond au problème de faire transiter le mot de passe en clair, ce qui est la question de ce fil.

            Oui, ça y répond, c'est même une des deux solutions que j'ai indiquées, à savoir : la mauvaise, où le mot de passe est stocké en clair sur le serveur.

    • [^] # Re: Mot de passe côté serveur

      Posté par  . Évalué à 2.

      • une bonne : sécuriser l'étape d'identification avec une couche de chiffrement comme TLS ;

      Tu parle d'utiliser un certificat client et de le faire valider par le serveur ? Si c'est le cas ça demande une machinerie importante (gestion d'une autorité de certification, vérifier la non révocation des certificats, la transmission des certificats de manière sure).

      S'il s'agit juste d'initier une connexion chiffrée, alors le problème reste l'authentification du client se fait avec une comparaison avec une clef hashée ou pas stocker sur le serveur.

      Je me demande si les systèmes de mot de passe à usage unique ou les authentifications en 2 étapes (généralement une web et un sms ou, plus original, 2 connexions web une pour le PC et l'autre par téléphone).

      Comment ça se passe pour toutes les authentifications web alternatives ? (OAuth, OpenId ou le dernier naît de chez Mozilla)

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

  • # Deux autres points

    Posté par  (site web personnel) . Évalué à 8.

    • le stockage de mots de passe pour un autre service (genre un fournisseur de webmail qui te demanderait ton mot de passe sur ton ancien webmail/boîte chez ton FAI pour l'import, ou un bureau virtuel qui vérifierait régulièrement ta boîte de courriel). Et on ne peut pas les hacher de fait.
    • malheureusement certains considèrent comme un plus marketing le fait de pouvoir renvoyer son mot de passe à l'utilisateur (donc stockage en clair).
  • # Vague et contradictoire

    Posté par  . Évalué à 10.

    La plupart des conseils donnés sont flous, pas forcément applicables, potentiellement contradictoires, voire incitent à faire n'importe quoi. Plus précisément :

    Comme il est possible par bruteforce (ou des techniques plus raffinées) de retrouver le mot de passe en clair et qu'il existe des tables précalculées (Rainbow table) pour les principaux algorithmes, il est aussi conseillé de saler les mots de passe. Cela consiste à ajouter des bits aléatoirement générés à la création du login et les ajouter au mot de passe avant d'utiliser la fonction de hachage.

    Le bon conseil à donner et d'utiliser une fonction de dérivation de clé connue, de lire sa documentation et de comprendre son interface. Le conseil tel qu'il est formulé ici incite le lecteur à implémenter sa propre technique de salage, ce qui va certainement résulter en de mauvais choix peu sécurisés (en particulier si c'est utilisé avec un algorithme de hachage n'ayant pas les bonnes propriétés). Au lieu de jouer à l'apprenti cryptographe, il vaut mieux utiliser des solutions déjà conçues par des spécialistes. Ça n'empêche pas de décrire l'idée sous-jacente (autant en plus comprendre ce qui est fait), mais en insistant pour éviter les mises en œuvres manuelles.

    L'intérêt est de ralentir le déchiffrage de votre base de données, et, à moins que vous n'authentifiez des milliers d'utilisateurs par seconde (ce qui peut arriver en cas d'attaque DDoS, il est donc bon de s'en protéger), ça ne devrait pas poser de problème de performances sur votre serveur.

    Merci le conseil contradictoire, c'est non-clair au possible. Je dois utiliser des algorithmes couteux en ressource, ou plutôt essayer de me protéger des DDoS ? Tu veux dire qu'il ne faut pas faire ce que tu dis, ou qu'il faut faire autre chose que tu ne dis pas ? Ça pose problème ou pas finalement ?

    Les bibliothèques sont idéalement à inclure (mais cela représente certainement trop de travail pour être réellement fait)

    Donc il faut le faire ou il ne faut pas le faire ? Si ce n'est pas faisable en pratique, autant ne pas en parler, les gens ne le feront pas. Une bonne politique de sécurité doit prendre la faisabilité en compte.

    Et d'ailleurs ce conseil n'est-il pas contradictoire avec celui des distributions qui conseille au contraire d'utiliser les bibliothèques partagées, pour profiter des fixes de sécurité ? Tu parles d'autre chose, à un autre degré de la chaîne, qui s'applique dans d'autres circonstances ?

    L'usage de conteneurs dynamiques (listes chaînées, par exemple) permet de réduire drastiquement les risques de ce genre d'attaques, mais impliquent un coût en ressources (temps processeur et occupation mémoire notamment) plus élevé. Ces conteneurs ne sont donc pas la panacée.

    Donc je les utilise ou pas ? Si ce n'est pas la bonne solution, qu'est-ce qui est conseillé ici ?

    • [^] # Re: Vague et contradictoire

      Posté par  . Évalué à 4.

      e conseil tel qu'il est formulé ici incite le lecteur à implémenter sa propre technique de salage, ce qui va certainement résulter en de mauvais choix peu sécurisés

      Il y a un paragraphe qui a sauté avec les modification et qui écrivait en gros : « Ces techniques sont parfois disponibles dans les bibliothèques mais il est bon de vérifier qu'elles sont effectivement utilisées ».

      Ça pose problème ou pas finalement ?

      Ça dépend si le login est vulnérable aux attaques DDoS ou s'il y a des protection contre ça.

      Donc je les utilise ou pas ?

      Si tu n'es pas capable de peser le pour et le contre, il vaut mieux ne jamais rien faire.

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

  • # Canaries

    Posté par  . Évalué à 10. Dernière modification le 19 avril 2013 à 22:07.

    Pour éviter les problèmes de buffer overflow, il existe notamment la technique du canarie. Cela consiste à placer des caractères connus après un buffer et de les rechercher par la suite. Si on ne les retrouve pas c'est que le buffer a été réécrit / dépassé.

    Plus d'informations sur cette page wikipedia (en anglais).

    Il existe plusieurs options de compilation gcc pour les utiliser
    -fstack-protector
    -fstack-protector-all
    -Wstack-protector

    voir cet article (en anglais aussi)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.