web-dev-qa-db-fra.com

Cryptage du mot de passe côté client

Duplicate possible:
À propos du système de hachage du 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 était d'utiliser MD5 chiffrement hachage côté serveur. Mais le problème est que les mots de passe restent en texte brut jusqu'à ce qu'ils arrivent sur le serveur, ce qui signifie que le mot de passe peut être capturé à l'aide de la surveillance du trafic. Donc, ce que je veux, c'est utiliser un mécanisme de cryptage/hachage du mot de passe côté client et envoyer le mot de passe crypté/haché. Quelqu'un peut-il dire quel est le moyen de le faire?

68
dinesh senartne

Ce ne sera pas sécurisé, et il est simple d'expliquer pourquoi:

Si vous hachez le mot de passe côté client et utilisez ce jeton au lieu du mot de passe, il sera alors peu probable qu'un attaquant découvre le mot de passe.

Mais, l'attaquant n'a pas besoin, de savoir quel est le mot de passe, car votre serveur n'attend plus le mot de passe, il attend le jeton. Et l'attaquant connaît connaît le jeton car il est envoyé via HTTP non chiffré!

Maintenant, il serait peut-être possible de pirater une forme de cryptage défi/réponse, ce qui signifie que le même mot de passe produira un jeton différent à chaque demande. Toutefois, cela nécessitera que le mot de passe soit stocké dans un format déchiffrable sur le serveur, ce qui n'est pas idéal, mais pourrait constituer un compromis approprié.

Et enfin, voulez-vous vraiment demander aux utilisateurs d'activer javascript avant de pouvoir se connecter à votre site Web?

Dans tous les cas, SSL n’est plus une solution onéreuse ni particulièrement difficile à mettre en place.

114
Gareth

Vous avez besoin d'une bibliothèque capable de chiffrer votre entrée côté client et de la transférer sur le serveur sous forme chiffrée.

Vous pouvez utiliser les bibliothèques suivantes:

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

Mise à jour après 3 ans:

Mise à jour après 4 ans (Wohoo!)

Toujours pas convaincu? Moi non plus :)

95
Herr

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 saisis par l'utilisateur
    • calcule le hachage du mot de passe, en obtenant h(pw) (qui est 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, appelle-le h(all)
    • envoie au serveur username, #C et h(all)
  • Serveur
    • récupère h(pw)' pour le username spécifié, à partir du DB
    • maintenant, il a tous les éléments pour calculer h(all'), comme l'a fait le client
    • si h(all) = h(all') alors h(pw) = h(pw)', presque certainement

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

42
bluish

Ce type de protection est normalement fourni en utilisant HTTPS , de sorte 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 Apache contient un guide SSL Configuration HOW-TO qui peut vous être utile. (merci à l'utilisateur G. Qyy pour le lien)

13
Justin

J'ai répertorié un code JavaScript complet pour la création d'un MD5 en bas, mais il est vraiment inutile de disposer d'une connexion sécurisée pour plusieurs raisons.

Si vous MD5 le mot de passe et stocker ce MD5 dans votre base de données, le MD5 est le mot de passe. Les gens peuvent dire exactement ce qu'il y a dans votre base de données. En gros, vous venez de rendre le mot de passe plus long, mais il n'est toujours pas sécurisé si c'est ce que vous stockez dans votre base de données.

Si vous dites: "Eh bien, je vais MD5 le MD5" vous manquez le point. En examinant le trafic réseau ou dans votre base de données, je peux usurper votre site Web et lui envoyer le MD5. Certes, cela est beaucoup plus difficile que de simplement réutiliser un mot de passe en texte brut, mais cela reste une faille de sécurité.

Surtout si vous ne pouvez pas saler le côté client de hachage sans envoyer le sel sur le réseau sans chiffrement, rendant ainsi le salage inutile. Sans sel ou avec un sel connu, je peux attaquer le hachage par la force brute et déterminer le mot de passe.

Si vous voulez faire ce genre de choses avec des transmissions non cryptées, vous devez utiliser une technique de cryptage à clé publique/clé privée . Le client chiffre en utilisant votre clé publique puis vous le déchiffrez avec votre clé privée alors vous MD5 le mot de passe (en utilisant un sel unique de l'utilisateur) et le stockez dans votre base de données. Voici ne bibliothèque de clés JavaScript/publique GPL JavaScript .

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();
}
10
Mike Bethany

Vous avez marqué cette question avec l’étiquette ssl , et SSL est la réponse. Curieuse.

5
user207421
4
Pascal Qyy

Il existe des bibliothèques MD5 disponibles pour javascript. N'oubliez pas que cette solution ne fonctionnera pas si vous devez prendre en charge des utilisateurs pour lesquels JavaScript n'est pas disponible.

La solution la plus courante consiste à utiliser HTTPS. Avec HTTPS, le cryptage SSL est négocié entre votre serveur Web et le client, cryptant de manière transparente tout le trafic.

2
Zack Bloom

Pour une situation similaire, j’ai utilisé ceci PKCS # 5: norme de cryptographie basée sur un mot de passe des laboratoires RSA. Vous pouvez éviter de stocker le mot de passe en le remplaçant par quelque chose qui ne peut être généré qu'à partir du mot de passe (en une phrase). Il y a quelques implémentations de JavaScript.

0