85 votes

Cryptage du mot de passe côté client

Duplicata possible :
A propos du système de hachage de mot de passe côté client

Je dois sécuriser les mots de passe des utilisateurs de mon site web. Ce que j'ai fait, c'est utiliser MD5 chiffrement côté serveur. Mais le problème est que les mots de passe restent en texte clair jusqu'à ce qu'ils arrivent au serveur, ce qui signifie que le mot de passe peut être capturé à l'aide de la surveillance du trafic. Ce que je veux donc, c'est utiliser un mécanisme de cryptage/hachage de mot de passe côté client et envoyer le mot de passe crypté/haché. Quelqu'un peut-il me dire comment procéder ?

40 votes

MD5 n'est pas un cryptage. Quelque chose de crypté peut être décrypté, par définition

0 votes

C'est vrai Gareth. MD5 est un algorithme de hachage cryptographique à sens unique, ce n'est pas un cryptage car, comme vous l'avez dit à juste titre, il ne peut pas être décrypté à l'aide d'une formule. Il ne peut être attaqué que par force brute ou vérifié par rapport à une table de hachages connus.

0 votes

Oui, et lorsque vous stockez le hachage MD5 (ou tout autre type de hachage) d'un mot de passe, n'oubliez jamais d'utiliser un sel ! ( owasp.org/index.php/Hashing_Java#Why_add_salt_.3F )

135voto

Gareth Points 42402

Cela ne sera pas sûr, et il est facile d'expliquer pourquoi :

Si vous hachurez le mot de passe côté client et que vous utilisez ce jeton au lieu du mot de passe, il est peu probable qu'un pirate découvre le mot de passe.

Mais l'attaquant ne besoin pour connaître le mot de passe, car votre serveur n'attend plus le mot de passe, mais le jeton. Et l'attaquant hace connaît le jeton parce qu'il est envoyé par HTTP non crypté !

Aujourd'hui, il pourrait être possible de pirater une forme de cryptage de type défi/réponse, ce qui signifie que le même mot de passe produira un jeton différent à chaque demande. Toutefois, il faudra pour cela que le mot de passe soit stocké dans un format décryptable sur le serveur, ce qui n'est pas idéal, mais pourrait constituer un compromis acceptable.

Enfin, souhaitez-vous vraiment exiger des utilisateurs qu'ils activent javascript avant de pouvoir se connecter à votre site web ?

En tout état de cause, SSL n'est plus une solution coûteuse ou particulièrement difficile à mettre en place

36 votes

+1 pour expliquer pourquoi l'idée est fondamentalement erronée. SSL / TLS est la meilleure solution dans ce cas.

1 votes

Je ne comprends pas très bien votre réponse.En effet,même si l'attaquant connaît le jeton,une fois qu'il va l'utiliser,il doit utiliser la page de connexion par défaut.S'il utilise ce jeton (mot de passe crypté),il est à nouveau crypté et envoyé au serveur.Il ne réussira donc pas.

17 votes

Non, un attaquant n'a pas besoin d'utiliser la page de connexion. Un formulaire web est une manière de construire une requête web à envoyer à un serveur, mais il est no le seul moyen. Il existe de nombreuses façons de se connecter à un serveur et de reproduire une requête comme si elle était effectuée par un navigateur web

118voto

Herr K Points 990

Vous avez besoin d'une bibliothèque capable de crypter vos données côté client et de les transférer au serveur sous forme cryptée.

Vous pouvez utiliser les librairies suivantes :

  • jCryptage . Chiffrement asymétrique client-serveur sur Javascript

Mise à jour après 3 ans (2013) :

Mise à jour après 4 ans (2014) :

2 votes

Exactement ce dont il a besoin, bonne réponse.

11 votes

+1 pour avoir été la seule réponse ici à fournir la solution à ce que le PO voulait (c'est-à-dire le cryptage côté client).

2 votes

Merci à vous tous :) J'ai essayé d'être clair.

61voto

bluish Points 5503

Je choisirais cette solution simple .

En résumé :

  • Client "Je veux me connecter"
  • Le serveur génère un nombre aléatoire #S et l'envoie au client
  • Client
    • lit le nom d'utilisateur et le mot de passe tapés par l'utilisateur
    • calcule le hachage du mot de passe, en obtenant h(pw) (ce qui est stocké dans la base de données)
    • génère un autre nombre aléatoire #C
    • concatène h(pw) + #S + #C et calcule son hachage, appelez-le h(all)
    • envoie au serveur username , #C y h(all)
  • Serveur
    • récupère h(pw)' pour le username à partir de la base de données
    • il dispose maintenant de tous les éléments pour calculer h(all') comme l'a fait le client
    • si h(all) = h(all') puis h(pw) = h(pw)' , presque certainement

Personne ne peut répéter la demande de connexion en tant qu'utilisateur spécifié. #S ajoute une composante variable au hachage, à chaque fois (c'est fondamental). #C ajoute du bruit supplémentaire.

2 votes

Je dois dire que ce fil est incroyable, je suis ravi et ta réponse est sous-estimée, bien sûr, même si elle est très simple, elle explique un concept fondamental. Je suis dans une situation similaire à celle de l'auteur original et je voulais vous demander quelque chose à propos de votre solution.

0 votes

(Désolé, j'ai appuyé sur entrée par accident et publié un commentaire incomplet) Quelles sont les chances qu'un attaquant intercepte le #S en... Je ne sais pas, peut-être en utilisant une carte réseau en mode promiscuous ou en clonant une adresse MAC et en l'utilisant ensuite pour décrypter h(all). Je veux dire qu'il aura #S et puisque #C est nu, il pourrait avoir le mot de passe haché.

1 votes

Merci de votre attention ! Je pense que les chances sont très faibles, si les nombres aléatoires sont suffisamment grands. Une simple modification de la chaîne source (dans notre cas, chaque connexion correspond à deux nouveaux nombres aléatoires) produit un hachage complètement différent. De plus, l'inversion du hachage est très difficile si la chaîne source n'est pas dans un dictionnaire. Mais peut-être que quelqu'un de plus expert que moi pourra vous aider.

16voto

Justin Points 42106

Ce type de protection est normalement assuré par l'utilisation de HTTPS afin que toutes les communications entre le serveur web et le client soient cryptées.

Les instructions exactes pour y parvenir dépendent de votre serveur web.

La documentation d'Apache contient une page Configuration de SSL : mode d'emploi qui peut être utile. (merci à l'utilisateur G. Qyy pour le lien)

0 votes

Il a déjà dit qu'il ne pouvait pas utiliser HTTPS. Vous ne pouvez pas l'ignorer dans votre réponse.

3 votes

@Mike Où a-t-il dit cela ? J'ai

0 votes

.

10voto

J'ai listé un JavaScript complet pour créer un MD5 en bas de page mais c'est vraiment inutile sans une connexion sécurisée pour plusieurs raisons.

Si vous utilisez le MD5 pour le mot de passe et que vous le stockez dans votre base de données, le MD5 est le mot de passe. Les gens peuvent savoir exactement ce qui se trouve dans votre base de données. En fait, vous avez simplement allongé le mot de passe, mais il n'est toujours pas sécurisé si c'est ce que vous stockez dans votre base de données.

Si vous dites : "Je vais faire un MD5 du MD5", vous ne comprenez pas. En examinant le trafic réseau ou votre base de données, je peux usurper votre site web et lui envoyer le MD5. Il est vrai que c'est beaucoup plus difficile que de réutiliser un mot de passe en texte clair, mais cela reste une faille de sécurité.

Mais surtout, il est impossible de saler le hachage côté client sans envoyer le sel en clair sur le réseau, ce qui rend le salage inutile. Sans sel ou avec un sel connu, je peux attaquer le hachage par force brute et découvrir le mot de passe.

Si vous voulez faire ce genre de choses avec des transmissions non cryptées, vous devez utiliser un système de cryptage. chiffrement par clé publique/privée technique. Le client crypte à l'aide de votre clé publique, puis vous décryptez de votre côté à l'aide de votre clé privée. puis vous MD5 le mot de passe (en utilisant un sel unique pour l'utilisateur) et vous le stockez dans votre base de données. Voici un exemple une bibliothèque de clés publiques/privées JavaScript sous licence GPL .

Quoi qu'il en soit Voici le code JavaScript permettant de créer un MD5 côté client (pas mon code) :

/**
*
*  MD5 (Message-Digest Algorithm)
*  http://www.webtoolkit.info/
*
**/

var MD5 = function (string) {

    function RotateLeft(lValue, iShiftBits) {
        return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
    }

    function AddUnsigned(lX,lY) {
        var lX4,lY4,lX8,lY8,lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    }

    function F(x,y,z) { return (x & y) | ((~x) & z); }
    function G(x,y,z) { return (x & z) | (y & (~z)); }
    function H(x,y,z) { return (x ^ y ^ z); }
    function I(x,y,z) { return (y ^ (x | (~z))); }

    function FF(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function GG(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function HH(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function II(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function ConvertToWordArray(string) {
        var lWordCount;
        var lMessageLength = string.length;
        var lNumberOfWords_temp1=lMessageLength + 8;
        var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
        var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
        var lWordArray=Array(lNumberOfWords-1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while ( lByteCount < lMessageLength ) {
            lWordCount = (lByteCount-(lByteCount % 4))/4;
            lBytePosition = (lByteCount % 4)*8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount-(lByteCount % 4))/4;
        lBytePosition = (lByteCount % 4)*8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
        lWordArray[lNumberOfWords-2] = lMessageLength<<3;
        lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
        return lWordArray;
    };

    function WordToHex(lValue) {
        var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
        for (lCount = 0;lCount<=3;lCount++) {
            lByte = (lValue>>>(lCount*8)) & 255;
            WordToHexValue_temp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
        }
        return WordToHexValue;
    };

    function Utf8Encode(string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    };

    var x=Array();
    var k,AA,BB,CC,DD,a,b,c,d;
    var S11=7, S12=12, S13=17, S14=22;
    var S21=5, S22=9 , S23=14, S24=20;
    var S31=4, S32=11, S33=16, S34=23;
    var S41=6, S42=10, S43=15, S44=21;

    string = Utf8Encode(string);

    x = ConvertToWordArray(string);

    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;

    for (k=0;k<x.length;k+=16) {
        AA=a; BB=b; CC=c; DD=d;
        a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
        d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
        c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
        b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
        a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
        d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
        c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
        b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
        a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
        d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
        c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
        b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
        a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
        d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
        c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
        b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
        a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
        d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
        c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
        b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
        a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
        d=GG(d,a,b,c,x[k+10],S22,0x2441453);
        c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
        b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
        a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
        d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
        c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
        b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
        a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
        d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
        c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
        b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
        a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
        d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
        c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
        b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
        a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
        d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
        c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
        b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
        a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
        d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
        c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
        b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
        a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
        d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
        c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
        b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
        a=II(a,b,c,d,x[k+0], S41,0xF4292244);
        d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
        c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
        b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
        a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
        d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
        c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
        b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
        a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
        d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
        c=II(c,d,a,b,x[k+6], S43,0xA3014314);
        b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
        a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
        d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
        c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
        b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
        a=AddUnsigned(a,AA);
        b=AddUnsigned(b,BB);
        c=AddUnsigned(c,CC);
        d=AddUnsigned(d,DD);
    }

    var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);

    return temp.toLowerCase();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X