Development Tip

클라이언트 측에서 암호 암호화

yourdevel 2020. 11. 2. 19:51
반응형

클라이언트 측에서 암호 암호화


중복 가능성 :
클라이언트 측 암호 해싱 시스템 정보

내 웹 사이트 사용자의 암호를 보호해야합니다. 내가 한 것은 서버 측에서 MD5 암호화 해싱을 사용하는 것 입니다. 그러나 문제는 암호가 서버에 도착할 때까지 일반 텍스트로 유지된다는 것입니다. 즉, 트래픽 모니터링을 사용하여 암호를 캡처 할 수 있습니다. 그래서 내가 원하는 것은 클라이언트 측 암호 암호화 / 해싱 메커니즘을 사용하고 암호화 / 해시 된 암호를 보내는 것입니다. 아무도 이것을하는 방법이 무엇인지 말할 수 있습니까?


이것은 안전하지 않으며 이유를 간단하게 설명 할 수 있습니다.

클라이언트 측에서 암호를 해시하고 암호 대신 해당 토큰을 사용하면 공격자가 암호가 무엇인지 알아 내지 못할 것입니다.

그러나 서버가 더 이상 암호를 예상하지 않고 토큰을 기대하기 때문에 공격자는 암호가 무엇인지 알아낼 필요 가 없습니다. 그리고 공격자 토큰이 암호화되지 않은 HTTP를 통해 전송되기 때문에 토큰을 알고 있습니다!

이제 일종의 시도 / 응답 형태의 암호화를 함께 해킹 할 수 있습니다. 즉, 동일한 암호가 각 요청마다 다른 토큰을 생성한다는 의미입니다. 그러나 이렇게하려면 암호가 서버에 암호 해독 가능한 형식으로 저장되어야합니다. 이는 이상적이지 않지만 적절한 타협이 될 수 있습니다.

마지막으로 사용자가 웹 사이트에 로그인하기 전에 자바 스크립트를 활성화하도록 요구 하시겠습니까?

어쨌든 SSL은 더 이상 비용이 많이 들거나 솔루션을 설정하기가 특히 어렵지 않습니다.


클라이언트 측에서 입력을 암호화하고 암호화 된 형식으로 서버로 전송할 수있는 라이브러리가 필요합니다.

다음 libs를 사용할 수 있습니다.

  • jCryption . 자바 스크립트를 통한 클라이언트-서버 비대칭 암호화

3 년 후 업데이트 :

4 년 후 업데이트 (Wohoo!)

아직도 확신이 없으세요? 나도 아니다 :)


이 간단한 솔루션을 선택 합니다 .

요약 :

  • 클라이언트 "로그인하고 싶습니다"
  • 서버는 난수를 생성 #S하여 클라이언트로 보냅니다.
  • 고객
    • 사용자가 입력 한 사용자 이름과 암호를 읽습니다.
    • 암호의 해시를 계산하여 h(pw)(DB에 저장된 것)
    • 다른 난수 생성 #C
    • h(pw) + #S + #C해시를 연결 하고 계산합니다.h(all)
    • 서버에 전송 username, #Ch(all)
  • 섬기는 사람
    • DB에서 h(pw)'지정된에 대한 검색username
    • 이제 h(all')클라이언트처럼 계산할 모든 요소 가 있습니다.
    • if h(all)= h(all')then h(pw)= h(pw)', 거의 확실 함

아무도 지정된 사용자로 로그인 요청을 반복 할 수 없습니다. #S매번 해시에 변수 구성 요소를 추가합니다 (기본). #C그것에 추가 소음을 추가합니다.


이러한 종류의 보호는 일반적으로 HTTPS 를 사용하여 제공 되므로 웹 서버와 클라이언트 간의 모든 통신이 암호화됩니다.

이를 달성하는 방법에 대한 정확한 지침은 웹 서버에 따라 다릅니다.

Apache 문서에는 도움이 될 수 있는 SSL 구성 하우투 가이드가 있습니다. ( 링크에 대한 사용자 G. Qyy 에게 감사드립니다 )


맨 아래에 MD5를 만들기위한 완전한 JavaScript를 나열했지만 몇 가지 이유로 보안 연결 없이는 정말 무의미합니다.

암호를 MD5하고 해당 MD5를 데이터베이스에 저장하면 MD5가 암호입니다. 사람들은 데이터베이스에 무엇이 있는지 정확히 알 수 있습니다. 기본적으로 암호를 더 긴 문자열로 만들었지 만 데이터베이스에 저장하는 경우 여전히 안전하지 않습니다.

"음, MD5를 MD5 할게요"라고 말하면 요점을 놓친 것입니다. 네트워크 트래픽을 보거나 데이터베이스를 살펴보면 웹 사이트를 스푸핑하여 MD5로 보낼 수 있습니다. 물론 이것은 일반 텍스트 암호를 재사용하는 것보다 훨씬 어렵지만 여전히 보안 허점입니다.

무엇보다도 암호화되지 않은 'net을 통해 솔트를 보내지 않고 해시 클라이언트 측을 솔트 할 수 없으므로 솔팅을 무의미하게 만듭니다. 솔트없이 또는 알려진 솔트를 사용하면 해시를 무차별 공격하여 암호가 무엇인지 알아낼 수 있습니다.

암호화되지 않은 전송으로 이러한 종류의 작업을 수행하려면 공개 키 / 개인 키 암호화 기술 을 사용해야합니다 . 공개 키를 사용하여 클라이언트를 암호화은 당신은 당신의 개인 키와 끝에 해독 한 후 당신이 (사용자 고유의 소금을 사용하여) 암호를 MD5 및 데이터베이스에 저장합니다. 다음 은 JavaScript GPL 공개 / 비공개 키 라이브러리 입니다.

어쨌든 , 다음은 MD5 클라이언트 측 을 만드는 JavaScript 코드입니다 (내 코드가 아님).

/**
*
*  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();
}

이 질문에 태그를 지정했으며 SSL이 답입니다. 궁금한.


You can also simply use http authentication with Digest (Here some infos if you use Apache httpd, Apache Tomcat, and here an explanation of digest).

With Java, for interesting informations, take a look at :


There are MD5 libraries available for javascript. Keep in mind that this solution will not work if you need to support users who do not have javascript available.

The more common solution is to use HTTPS. With HTTPS, SSL encryption is negotiated between your web server and the client, transparently encrypting all traffic.


For a similar situation I used this PKCS #5: Password-Based Cryptography Standard from RSA laboratories. You can avoid storing password, by substituting it with something that can be generated only from the password (in one sentence). There are some JavaScript implementations.

참고URL : https://stackoverflow.com/questions/4121629/password-encryption-at-client-side

반응형