Javascript 客户端密码加密
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4121629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Password encryption at client side
提问by dinesh senartne
Possible Duplicate:
About password hashing system on client side
可能的重复:
关于客户端的密码散列系统
I have to secure the passwords of my web site users. What I did was use MD5 encryptionhashing in server side. But the problem is the passwords remain in plain text until it arrives at the server, which means that the password can be captured using traffic monitoring. So what I want is to use a client side password encryption/hashing mechanism and send the encrypted/hashed password.
Can anybody tell what is the way to do this?
我必须保护我的网站用户的密码。我所做的是在服务器端使用 MD5加密散列。但问题是密码在到达服务器之前一直以纯文本形式存在,这意味着可以使用流量监控来捕获密码。所以我想要的是使用客户端密码加密/散列机制并发送加密/散列密码。谁能告诉我有什么方法可以做到这一点?
回答by Gareth
This won't be secure, and it's simple to explain why:
这并不安全,原因很简单:
If you hash the password on the client side and use that token instead of the password, then an attacker will be unlikely to find out what the password is.
如果您在客户端散列密码并使用该令牌而不是密码,那么攻击者就不太可能知道密码是什么。
But, the attacker doesn't needto find out what the password is, because your server isn't expecting the password any more - it's expecting the token. And the attacker doesknow the token because it's being sent over unencrypted HTTP!
但是,攻击者不需要找出密码是什么,因为您的服务器不再需要密码 - 它需要令牌。攻击者确实知道令牌,因为它是通过未加密的 HTTP 发送的!
Now, it might be possible to hack together some kind of challenge/response form of encryption which means that the same password will produce a different token each request. However, this will require that the password is stored in a decryptable format on the server, something which isn't ideal, but might be a suitable compromise.
现在,有可能将某种质询/响应形式的加密组合在一起,这意味着相同的密码将在每个请求中生成不同的令牌。但是,这将要求密码以可解密的格式存储在服务器上,这并不理想,但可能是一个合适的折衷方案。
And finally, do you really want to require users to have javascript turned on before they can log into your website?
最后,您真的要要求用户在登录您的网站之前打开 javascript 吗?
In any case, SSL is neither an expensive or especially difficult to set up solution any more
无论如何,SSL 不再是一种昂贵或特别难以设置的解决方案
回答by Herr
You need a library that can encrypt your input on client side and transfer it to the server in encrypted form.
您需要一个可以在客户端加密您的输入并以加密形式将其传输到服务器的库。
You can use following libs:
您可以使用以下库:
- jCryption. Client-Server asymmetric encryption over Javascript
- jCryption。基于 Javascript 的客户端 - 服务器非对称加密
Update after 3 years:
3年后更新:
Update after 4 years (Wohoo!)
4 年后更新(哇!)
Still not convinced? Neither am I :)
还是不相信?我也不 :)
- OpenPGP.JS - Put the OpenPGP format everywhere- runs in JS so you can use it in your web apps, mobile apps & etc.
- OpenPGP.JS - 将 OpenPGP 格式放在任何地方- 在 JS 中运行,因此您可以在您的网络应用程序、移动应用程序等中使用它。
回答by bluish
I would choose this simple solution.
我会选择这个简单的解决方案。
Summarizing it:
总结一下:
- Client "I want to login"
- Server generates a random number
#S
and sends it to the Client - Client
- reads username and password typed by the user
- calculates the hash of the password, getting
h(pw)
(which is what is stored in the DB) - generates another random number
#C
- concatenates
h(pw) + #S + #C
and calculates its hash, call ith(all)
- sends to the server
username
,#C
andh(all)
- Server
- retrieves
h(pw)'
for the specifiedusername
, from the DB - now it has all the elements to calculate
h(all')
, like Client did - if
h(all)
=h(all')
thenh(pw)
=h(pw)'
, almost certainly
- retrieves
- 客户端“我要登录”
- 服务器生成一个随机数
#S
并发送给客户端 - 客户
- 读取用户输入的用户名和密码
- 计算密码的哈希值,得到
h(pw)
(这是存储在数据库中的内容) - 生成另一个随机数
#C
- 连接
h(pw) + #S + #C
并计算它的哈希值,调用它h(all)
- 发送到服务器
username
,#C
和h(all)
- 服务器
- 从数据库中检索
h(pw)'
指定username
的 - 现在它拥有了所有要计算的元素
h(all')
,就像客户所做的那样 - if
h(all)
=h(all')
thenh(pw)
=h(pw)'
,几乎可以肯定
- 从数据库中检索
No one can repeat the request to log in as the specified user. #S
adds a variable component to the hash, each time (it's fundamental). #C
adds additional noise in it.
任何人都不能重复以指定用户身份登录的请求。#S
每次都向散列添加一个变量组件(这是基本的)。#C
在其中添加额外的噪音。
回答by Justin
This sort of protection is normally provided by using HTTPS, so that all communication between the web server and the client is encrypted.
这种保护通常是通过使用HTTPS提供的,因此 Web 服务器和客户端之间的所有通信都是加密的。
The exact instructions on how to achieve this will depend on your web server.
如何实现这一点的确切说明将取决于您的 Web 服务器。
The Apache documentation has a SSL Configuration HOW-TOguide that may be of some help. (thanks to user G. Qyyfor the link)
Apache 文档有一个SSL 配置 HOW-TO指南,可能会有所帮助。(感谢用户G. Qyy提供链接)
回答by Justin
I've listed a complete JavaScript for creating an MD5 at the bottom but it's really pointless without a secure connection for several reasons.
我在底部列出了用于创建 MD5 的完整 JavaScript,但由于多种原因,如果没有安全连接,它真的毫无意义。
If you MD5 the password and store that MD5 in your database then the MD5 is the password. People can tell exactly what's in your database. You've essentially just made the password a longer string but it still isn't secure if that's what you're storing in your database.
如果您对密码进行 MD5 并将该 MD5 存储在您的数据库中,那么 MD5 就是密码。人们可以准确地说出您的数据库中的内容。您实际上只是将密码设置为更长的字符串,但如果这是您在数据库中存储的内容,它仍然不安全。
If you say, "Well I'll MD5 the MD5" you're missing the point. By looking at the network traffic, or looking in your database, I can spoof your website and send it the MD5. Granted this is a lot harder than just reusing a plain text password but it's still a security hole.
如果你说,“好吧,我将 MD5 MD5”,你就没有抓住重点。通过查看网络流量或查看您的数据库,我可以欺骗您的网站并将其发送 MD5。当然,这比重复使用纯文本密码要困难得多,但它仍然是一个安全漏洞。
Most of all though you can't salt the hash client side without sending the salt over the 'net unencrypted therefore making the salting pointless. Without a salt or with a known salt I can brute force attack the hash and figure out what the password is.
最重要的是,尽管您不能在没有通过未加密的网络发送盐的情况下对哈希客户端进行加盐,因此使加盐毫无意义。在没有盐或已知盐的情况下,我可以蛮力攻击散列并找出密码是什么。
If you are going to do this kind of thing with unencrypted transmissions you need to use a public key/private key encryptiontechnique. The client encrypts using your public key then you decrypt on your end with your private key thenyou MD5 the password (using a user unique salt) and store it in your database. Here's a JavaScript GPL public/private key library.
如果您打算使用未加密的传输进行此类操作,则需要使用公钥/私钥加密技术。客户端使用您的公钥加密,然后您用您的私钥解密,然后您对密码进行 MD5(使用用户唯一的盐)并将其存储在您的数据库中。这是一个 JavaScript GPL 公钥/私钥库。
Anyway, here is the JavaScript code to create an MD5client side (not my code):
无论如何,这是创建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();
}
回答by user207421
回答by Pascal Qyy
You can also simply use http authenticationwith Digest(Here some infos if you use Apache httpd, Apache Tomcat, and here an explanation of digest).
您也可以简单地将http 身份验证与Digest 一起使用(如果您使用 Apache httpd、Apache Tomcat,这里有一些信息,这里有一个对digest 的解释)。
With Java, for interesting informations, take a look at :
使用 Java,有关有趣的信息,请查看:
- Understanding Login Authentication
- HTTP Digest Authentication Request & Response Examples
- HTTP Authentication Woes
- Basic Authentication For JSP Page(it's not digest, but I think it's an interesting source)
- 了解登录身份验证
- HTTP 摘要身份验证请求和响应示例
- HTTP 身份验证问题
- JSP 页面的基本身份验证(它不是摘要,但我认为这是一个有趣的来源)
回答by Zack Bloom
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.
有可用于 javascript 的 MD5 库。请记住,如果您需要支持没有可用 javascript 的用户,则此解决方案将不起作用。
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.
更常见的解决方案是使用 HTTPS。使用 HTTPS,您的 Web 服务器和客户端之间会协商 SSL 加密,透明地加密所有流量。
回答by Dimitrios Mistriotis
For a similar situation I used this PKCS #5: Password-Based Cryptography Standardfrom 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.
对于类似的情况,我使用了来自 RSA 实验室的PKCS #5: Password-Based Cryptography Standard。您可以避免存储密码,方法是用只能从密码生成的东西(用一句话)代替它。有一些 JavaScript 实现。