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();
}
Verwendung
MD5("whatever");
Vielleicht so etwas wie einen Gravatar schnappen.
Wäre es eine gute oder schlechte Idee, ein Passwort in einem Anmeldeformular beim Absenden durch den MD5-String anstelle des tatsächlichen Passworts zu ersetzen?
Ich würde denken, es würde zusätzliche Sicherheit schaffen... Bitte korrigieren Sie mich, wenn ich falsch liege..
Ich glaube nicht. Wenn der Benutzer JavaScript deaktiviert hat, wird das Passwort immer noch im Klartext gesendet und es gibt keine Möglichkeit für den Server zu wissen, ob es sich um einen MD5-verschlüsselten String oder das Passwort des Benutzers handelt.
Ja, das ist eine gute Idee.
@Johnathan Barett
Aber der Server könnte beide Möglichkeiten ausprobieren ;)
(in PHP „$correct = $_GET[„pwd“] == $password || md5($_GET[„pwd“]) == $password;“)
Es wäre nur dann großartig, wenn es auf der Serverseite passiert.
MD5 ist heutzutage lächerlich einfach zu entschlüsseln, und die Verwendung von SSL bewirkt im Grunde dasselbe, aber viel besser (und für *alle* zwischen Client und Server gesendeten und empfangenen Daten).
Dennoch kann Verschleierungssicherheit oft trotzdem eine gute Idee sein.
Bezüglich der Frage, ob JavaScript aktiviert/deaktiviert ist, wäre es sehr einfach, der Anforderung durch JavaScript ein zusätzliches Datenelement hinzuzufügen, in welchem Fall der Server nur auf die An- oder Abwesenheit dieses Elements achten müsste (Abwesenheit impliziert, dass JavaScript deaktiviert war und der String ohne vorheriges Hashing gesendet wurde).
Ich würde **dringend davon abraten**, sowohl die gehashte als auch die un-gehashte Version serverseitig zu prüfen. Ein Schloss sollte sich nur mit dem richtigen Schlüssel öffnen lassen, nicht versuchen, zwei verschiedene Schlüssel zu suchen und beide zu akzeptieren.
Zu Megatrons Antwort: Das würde nichts daran ändern, dass der String un-gehasht vom Client an den Server gesendet wird, also beantwortet es die Frage nicht wirklich.
Warum nicht einfach die md5() MySQL-Funktion verwenden?
Weil er kein MySQL benutzt. Ich gehe mal davon aus, dass Sie die PHP MD5-Funktion meinen. Das Problem dabei ist, wie nimmt man eine JavaScript-Eingabe und führt sie durch eine PHP-Funktion? So wie beim Abrufen eines Gravatars, der Benutzer gibt eine E-Mail-Adresse ein, wie übergibt man diesen Wert an eine PHP-Funktion, ohne eine weitere Seite im Hintergrund zu laden, um das Ergebnis zurückzusenden.
Nein, ich spreche von der md5 MySQL-Funktion, für die es eine äquivalente Funktion für SQL Server oder jeden anderen verwendeten Datenbankmanager gibt. Wenn Sie Passwörter verschlüsseln, nehme ich an, Sie speichern sie in einer Datenbank.
Passwörter sollten nicht mit MD5 gespeichert werden, da es nie als Verschlüsselungsalgorithmus konzipiert war. Es gibt jedoch andere Anwendungsfälle für das Hashing auf Client-Seite, z. B. zum Vergleichen von Prüfsummen.
Hmmm... Sie schlagen also vor: Klartext-Passwort zu MD5 (egal ob Frontend oder Backend implementiert) und dann das MD5 verschlüsseln anstatt des Klartext-Passworts. Ich finde das ziemlich schlau.
Ich weiß genau, wovon Sie sprechen, aber es geht nicht um die Speicherung von Informationen, sondern um die Übertragung von Informationen über den Browser.
Hey, danke Jungs für das Teilen dieses unschätzbar wertvollen Skripts.
@Johnathan Barrett: Es gibt tatsächlich einen Weg für den Server zu wissen, ob JavaScript im Browser des Clients aktiviert war oder nicht.
Dazu fügen Sie ein verstecktes Feld namens „hasjavascript“ zu Ihrem Formular hinzu, mit dem Standardwert „false“, und mit JavaScript setzen Sie einfach den Wert dieses Feldes auf „true“.
Überprüfen Sie dann im serverseitigen Code den Wert der GET-Variable „hasjavascript“.
Das Hashing des Passworts mit JavaScript bewirkt lediglich, dass, wenn jemand die übermittelten Werte abfängt, er den Klartext nicht erkennen kann und (hoffentlich) mit diesem Passwort auf anderen Websites nicht einloggen kann.
Beachten Sie, dass er sich trotzdem auf Ihrer Website anmelden kann, indem er einfach das abgefangene gehashte Passwort sendet, wie es der Browser tun würde.
Um das zu verhindern, müssten Sie einen asymmetrischen Verschlüsselungsalgorithmus wie RSA verwenden.
Lesen Sie mehr dazu auf: http://en.wikipedia.org/wiki/Public-key_cryptography
Ich habe dies für Websites verwendet, bei denen der Kunde kein https wünscht (sie sind verrückt, ich weiß). Was ich tue, ist die Challenge-Authentifizierung (eigentlich habe ich sie von Yahoo! Mail gestohlen :P). Es ist einfach.
1) Generieren Sie einen zufälligen „Salt“ (generieren Sie eine zufällige Zeichenkette) und speichern Sie ihn in der Sitzung. Senden Sie ihn an den Browser.
2) Verketten Sie im Client den Salt und das Passwort und hashen Sie es mit MD5. Senden Sie das Ergebnis. Senden Sie auch den Salt.
3) Prüfen Sie auf dem Server, ob der Salt derselbe ist und ob md5(salt . password) übereinstimmt. Wenn nicht, generieren Sie einen NEUEN Salt und wiederholen Sie den Vorgang.
Wenn Sie das Passwort auf dem Server verschlüsseln müssen, tun Sie dasselbe, aber anstatt das Passwort zu vergleichen, vergleichen Sie das verschlüsselte Passwort (offensichtlich müssen Sie den Prozess der Passwortverschlüsselung der Datenbank im Browser nachbilden).
Dennoch ist das kein Ersatz für eine HTTPS-Verbindung.
Was die Erkennung angeht, ob der Client JavaScript aktiviert hat, machen Sie einfach das Formular nicht absendbar, es sei denn, der Client hat JS aktiviert. Verwenden Sie etwas wie action="javascript:;" und dann onsubmit für die tatsächliche Übermittlung (Sie müssten ein unsichtbares Formular erstellen).
Tolles Skript.
@alle und @ROMAC
Hallo, ich sehe, dass die obigen Threads nicht mehr sehr aktuell sind, aber vielleicht liest sie ja jemand im Jahr 2013 :-)
Ich halte es für ein sehr interessantes Thema, ob sensible Benutzerdaten wie Passwörter im Internet unverschlüsselt oder verschlüsselt/gehasht übertragen werden oder nicht. Auch, ob sie in der Datenbank verschlüsselt/gehasht gespeichert werden oder nicht.
Da ich sehr auf die Sicherheit der Benutzerdaten bedacht bin, habe ich Folgendes als meine bevorzugte Methode gewählt, wenn ich eine Website einrichte:
1. – Da heute niemand mehr JavaScript deaktiviert (er bekäme keine zeitgemäße Web-Erfahrung mehr, da fast keine Websites mehr ohne laufen) gehe ich davon aus, dass die Benutzer absolut zustimmen würden, JavaScript zu nutzen, um ihre eigene oder ihre Datensicherheit zu stärken.
2. – Im Registrierungsprozess fordere ich die E-Mail-Adresse als ersten Benutzernamen an und sende sie unverschlüsselt an den Server und Passwörter als MD5-Hash (seit einigen Monaten verwende ich SHA256 zum Hashing).
Nach erfolgreicher Registrierung, E-Mail-Verifizierung und erster Anmeldung kann er einen anderen Benutzernamen (oder eine Handynummer, siehe nächster Punkt 6.) festlegen.
3. – Es gibt verschiedene Möglichkeiten, serverseitig zu prüfen, ob das gesendete Passwort ein Hash (durch aktiviertes JS) ist oder nicht.
… – a) Verwenden Sie die obige Lösung von ROMAC, setzen Sie das versteckte Feld von „false“ auf „true“ (oder beliebige bekannte Werte).
… – b) Zählen Sie die Länge des Strings auf dem Server (wer zur Hölle wird ein 32 Zeichen langes Passwort oder 64 mit SHA256 verwenden?).
… – c) Erstellen Sie das Anmeldeformular mit JS/jQuery, wenn die Seite geladen wird, anstatt mit PHP/HTML (wenn JS deaktiviert ist, erscheint kein Anmeldeformular).
… – d) Fügen Sie keinen type=submit-Button hinzu, sondern einen type=button und senden Sie das Anmeldeformular mit JS und einem onclick-Event, auch wenn es mit PHP/HTML erstellt wurde (ohne Submit-Button funktioniert die ENTER-Taste nicht zum Absenden des Formulars).
4. – Serverseitig wird der eingehende Passwort-Hash erneut mit SHA256 zusammen mit einem zufälligen Salt gehasht. Der resultierende Hash und der Salt werden in der Datenbank gespeichert.
5. – Bei der Anmeldung wird das eingehende Passwort (angenommen als Hash) erneut mit dem gespeicherten Salt gehasht, in einer temporären Variable gespeichert, die mit dem in der Datenbank gespeicherten Hash verglichen wird. Wenn beide gleich sind... alles in Ordnung.
6. – Noch einmal unter Berücksichtigung von ROMACs Beitrag (asymmetrische Verschlüsselung wie RSA): Ich bevorzuge SMS-Schlüssel, wie es einige Online-Bankinstitute tun.
Wenn der Eigentümer einer Website zustimmt, da er nur minimale Kenntnisse über Sicherheit und Verschlüsselung hat, buche ich für ihn ein SMS-Konto (ich benutze den deutschen Anbieter goyya.com, da ich Deutscher bin :-)). Für sehr sensible Benutzerkontodaten muss der Benutzer einen SMS-Code auslösen (Handynummer erforderlich bei der Registrierung) und erhält zwei Codes: Den Salt aus der Serverdatenbank und eine 4-stellige Zufallszahl, die in der Sitzung gespeichert ist.
Nun wird der gesamte sensible Datenverkehr (und nur dieser) AES-verschlüsselt gesendet und kann im lokalen Browser mit jQuery AES-Bibliotheken entschlüsselt werden. Der Schlüssel wird nie über das Internet übertragen, er entspricht dem gehashten Passwort aus der Datenbank, erneut gehasht mit dem zufälligen SMS-Schlüssel.
Es klingt furchtbar? Hmm, vielleicht. Aber es funktioniert gut. Sobald es implementiert ist, ist es einfach zu handhaben und sicherer als RSA oder HTTPS, da asymmetrische Schlüssel überhaupt nicht über das Internet übertragen werden.
Nur eine Herausforderung gibt es, wenn der Benutzer seine Handynummer verliert oder wechselt... Im Benutzerprofil müssen ein oder zwei zuverlässige Handynummern von Freunden (Mutter, Vater) hinterlegt werden, die man verwenden kann, um die eigene Handynummer in den Benutzereinstellungen zu ändern. Dieser Freund oder zumindest sein Mobiltelefon muss zum Zeitpunkt der Anmeldung des Benutzers in seinem privaten Bereich vorhanden sein.
Im Premium-Tarif kostet es 85 Euro für 1000 SMS, was deutlich günstiger ist als ein HTTPS-Zertifikat für eine Website, vorausgesetzt, man muss nicht täglich auf seine persönlichen Kontoeinstellungen zugreifen.
@Rick, der Grund für die Nichtverwendung von https ist, dass neuere Browser eine große rote Warnung ausgeben: „DIESE SEITE IST UNVERTRAUEN!“ Wenn Sie ein selbstsigniertes Zertifikat verwenden.
Dies bedeutet im Grunde, dass https nur auf Websites verwendet werden kann, deren Budget sich ein Verisign-Zertifikat leisten kann, und auf Webspace, auf dem ein solches Zertifikat gehostet werden kann. Alle anderen müssen Klartextdaten senden. Nennen Sie es kontroproduktive Sicherheit.
Hallo Leute! Vielleicht weiß jemand, wie es möglich sein kann, dass ich einen String mit der oben beschriebenen JS-Funktion verschlüssle und wenn ich ihn mit Online-Diensten wie http://md5decrypt.net/en/ verschlüssle, sagt mir dieser, dass der Hash ungültig ist?
Danke, danke, danke
Vielen Dank, Bruder
Sie haben mich gerettet!
Danke für diese Lösung :)
Kann jemand die umgekehrte Logik dafür liefern? Ich meine die Entschlüsselung in JS selbst.
Je nach Ihren Bedürfnissen könnten Sie erwägen, eine REST-API aufzurufen, um das MD5 für Sie zu generieren oder sogar zu versuchen, es umzukehren. Schauen Sie sich https://crypto.apitools.zone/md5.html und https://crypto.apitools.zone/md5-decode.html an, beide sind sehr schnell.