对基于HTTP协议的密码传输安全的一些思考(附javascript脚本实现)

  如今的网络环境日益复杂,在局域网中不可避免被他人通过 ARP 欺骗来监听网络流量,或者网关本身监听流量,抑或 ISP 监听网络流量。而在以往的 HTTP 应用中,常见的做法是将密码和其他信息一同明文发送,这就导致用户的密码受到严重的威胁。近日对这个问题做了些许不成熟的思考,写出来和大家讨论一下。

  首先说一下登录密码。用户密码通常是用哈系算法计算后保存在数据库中,常用的有 MD5(就目前来看 MD5 已被证明是不安全的)和 SHA1,并且我们暂时假定服务器本身足够安全以至未经授权的任何人不会看到这些散列值,而网络中也暂时没有中间人攻击者(在后面会提到这个问题)。

  简单的想法就是在提交之前将用户密码通过同样的哈希算法计算,将散列值送回服务器比较。然而这是一种很不成熟的想法,因为嗅探者虽然不能得到密码明文,但是他同样可以使用这一散列值欺骗服务器获得授权。因此我们要在明文中加点盐——Salt。

  所谓 Salt 就是一段字符串,将它和哈希后的密码散列按照特定方式组合起来,然后对组合后的字符串再次应用哈希算法,将散列值送回服务器,服务器使用同样的 Salt 和组合方式组合 Salt 和数据库内的散列值,然后再次应用哈希算法,将结果和客户端传来的散列值比较判断。

  这样一来,嗅探者虽然能够看到 Salt 值和最终的散列值,已经组合方式,但除非他将这一散列值还原为明文,或者他一直刷新以使得服务器返回和本次嗅探得到的 Salt 一样的 Salt。事实上这两种情况的几率都比较小,而且成本很容易高过破解成功后带来的价值,因此这一破解将变得没有任何意义。

  就目前的情况来看,登录的密码安全似乎安全性有了不少提高(对于大部分只会用一些黑客软件的所谓“黑客”来说已经是难以破解了)。接下来的问题是注册时的密码传输安全。注册的时候服务器需要获取只应用过一次哈系算法的散列值,因此不能通过 Salt 来实现,这时就要用 RSA 非对称加密对散列值进行加密传输,然后在服务器端解密,这个想法比较简单。

  然而这样的传输方式对中间人攻击防范很弱,尤其是在注册的时候,中间人可以伪造一对 RSA 密钥,并替换发给用户的密钥,这样他就可以轻松的拿到一次哈系后的密码散列,甚至可以去掉相关的加密部分,使密码明文传送到攻击者那里。而这种攻击需要攻击者自行根据不同的网站编写不同的攻击程序,难度较高,因此只能说这些方法在安全性上有些许提高。

  最后简单说一下 .NET 下的实现方式。随机的 Salt 可以通过 RNGCryptoServiceProvider 生成,哈系算法建议使用 SHA1CryptoServiceProvider,RSA 算法则使用 RSACryptoServiceProvider,其中 Salt 和 RSA 的私钥可以保存在用户的 Session 中并加入生成时间,控制有效期。客户端方面需要自行编写 javascript 脚本实现 SHA1 和 RSA 加密,稍后我会整理出这 2 个脚本文件。此外,对于可以使用 AJAX 的网站,可以在点击提交时获取 Salt 或 RSA 公钥,然后计算后再提交,并减小有效期,增加中间人攻击的难度。过段时间我会给出完整的代码。

  另外还要提一下,任何安全性的增加都是牺牲性能的下降,在这里,客户端的加密函数较为庞大,此外客户端的 RSA 加密在我本人的 Core 2 Duo T9300 + 4GB 内存的笔记本上使用 1024 位密钥加密大概要好时 240 毫秒左右,而 SHA1 加密也要好费 30 毫秒左右。

  javascript 脚本实现参见 http://www.cnblogs.com/hust21941/archive/2008/08/16/1269463.html

posted @ 2008-08-15 12:04 田嵩 阅读(2722) 评论(31) 编辑 收藏

 回复 引用 查看   
#1楼2008-08-15 12:16 | 狼Robot      
楼主说的是B/S还是C/S?
 回复 引用 查看   
#2楼2008-08-15 12:20 | 狼Robot      
楼主说的MD5不安全?是指XMD5这样的东西么?
 回复 引用 查看   
#3楼[楼主]2008-08-15 12:21 | 田嵩      
@狼Robot
B/S模式,不过某些不需要加密传输的C/S模式也可以用这种方式。

 回复 引用 查看   
#4楼[楼主]2008-08-15 12:22 | 田嵩      
@狼Robot
山东大学的王晓云教授都用碰撞法从MD5散列快速推算出原文。

 回复 引用 查看   
#5楼2008-08-15 12:24 | 狼Robot      
B/S在客户端怎么加密呢?
 回复 引用 查看   
#6楼[楼主]2008-08-15 12:27 | 田嵩      
@狼Robot
用 javascript 实现。我已经实现了,还在做算法的优化,过段时间会贴出来的。

 回复 引用 查看   
#7楼2008-08-15 12:28 | 狼Robot      
javascript?那不是一样可以先把你的javascript拦截下来?这样不就知道你的加密方法了?
 回复 引用 查看   
#8楼2008-08-15 12:29 | 狼Robot      
--引用--------------------------------------------------
田嵩: @狼Robot
山东大学的王晓云教授都用碰撞法从MD5散列快速推算出原文。
--------------------------------------------------------
这个问题应该不大吧,你随便改改,他就碰撞不出来了.

 回复 引用 查看   
#9楼[楼主]2008-08-15 12:31 | 田嵩      
@狼Robot
我的加密方法就是 SHA1 和 RSA,但是 SHA1 是类似 MD5 那样的难以逆向破解的,RSA 的话客户端只知道公钥,而用公钥推算出解密用的私钥也是很困难的,所以即使知道我的方法也没关系。

 回复 引用 查看   
#10楼2008-08-15 12:51 | 亚历山大同志      
其实根本不需要破解MD5,只需要截获到js知道是如何加盐值就行了,这种方法还是不安全哈,不过对于只知道用嗅探器不会编程的菜鸟黑客来说倒是足够了,不过绝对不能用在和钱有关系的关键领域,如果那样的话最好还是写一个ActiveX控件来实现客户端加密或者Flash也行。
 回复 引用 查看   
#11楼[楼主]2008-08-15 12:53 | 田嵩      
@亚历山大同志
Salt 每次都不一样的。要更安全还是要 https 比较好,就是成本相对较高。

 回复 引用 查看   
#12楼2008-08-15 13:11 | 亚历山大同志      
--引用--------------------------------------------------
田嵩: @亚历山大同志
Salt 每次都不一样的。要更安全还是要 https 比较好,就是成本相对较高。
--------------------------------------------------------
盐值不一样也还是可以知道是如何生成如何使用盐值的撒,js代码本身有没编译过

 回复 引用 查看   
#13楼[楼主]2008-08-15 13:15 | 田嵩      
@亚历山大同志

Salt 由服务器生成传递给客户端 js 脚本,本身 Salt 的生成就是没有任何规律的,而且最终发回服务器的是对 Salt 和密码组合在一起的值应用哈希后的值

 回复 引用 查看   
#14楼2008-08-15 13:22 | 狼Robot      
--引用--------------------------------------------------
田嵩: @亚历山大同志
<br>
Salt 由服务器生成传递给客户端 js 脚本,本身 Salt 的生成就是没有任何规律的,而且最终发回服务器的是对 Salt 和密码组合在一起的值应用哈希后的值
--------------------------------------------------------

salt由服务器生成传递给客户端,那这个值还是一样可以被拦截到的嘛

 回复 引用 查看   
#15楼2008-08-15 13:24 | 狼Robot      
觉得用js脚本来进行加密,安全性还是不够,毕竟js还是明文传输到客户端的.安全的还是像那些网银什么的,用activex.
 回复 引用 查看   
#16楼[楼主]2008-08-15 13:31 | 田嵩      
@狼Robot
Salt 被拦截到也无所谓的
另外 js 脚本可以兼容 FireFox。。。

 回复 引用 查看   
#17楼2008-08-15 13:33 | 江大鱼      
传输层不加密,一切都是空谈
 回复 引用 查看   
#18楼[楼主]2008-08-15 13:35 | 田嵩      
@江大鱼
其实 https 也可以用中间人攻击来攻破。

 回复 引用 查看   
#19楼2008-08-15 16:24 | 江大鱼      
不能因为https有漏洞而放弃https, 在https的基础上运用你的方法岂不是更好。
 回复 引用 查看   
#20楼2008-08-15 16:28 | 江大鱼      
@田嵩
--引用--------------------------------------------------
田嵩: @狼Robot
山东大学的王晓云教授都用碰撞法从MD5散列快速推算出原文。
--------------------------------------------------------
要能真是推算出原文那就是宇宙的奇迹阿,
一部电影压缩成32个字符,然后放到网上, 另一个人把这32个字符快速推算出原文.....

 回复 引用 查看   
#21楼[楼主]2008-08-15 16:34 | 田嵩      
@江大鱼
这种方法只是一些无法用https的小网站的一个简易的措施。

@江大鱼
没说清楚。。。不是推出原文了,只是推出拥有相同散列值的

 回复 引用 查看   
#22楼2008-08-15 19:39 | Gray Zhang      
如果在用户机上使用函数钩子的话,如果知道函数签名,完全可以截获加密前的信息(传入加密函数的参数),上回的解决方案是随机产生函数名
 回复 引用 查看   
#23楼[楼主]2008-08-15 20:48 | 田嵩      
@Gray Zhang
所以我说是传输时候的安全。。。要是中了键盘记录的木马那就只能用ActiveX或者软键盘一类的才可以了

 回复 引用 查看   
#24楼2008-08-15 21:02 | Gray Zhang      
我记得,王小云破解MD5的方法,不是算出明文,而是算出一个可以得到相同MD5结果的内容
如果是这样的话,王小云的方法只能根据一次MD5的结果算出冲撞值,而如果连续MD5两次的话,他先把结果“MD5冲撞”,但冲撞的结果并不是原本一次MD5后的值,因此他没法再计算最原始的冲撞……
好难解释,我的最终意思是,不需要用SALT,直接MD5两次就有安全保证了……

 回复 引用 查看   
#25楼2008-08-15 21:37 | Cat Chen      
直接用https就可以了。
 回复 引用 查看   
#26楼2008-08-15 21:38 | Cat Chen      
@Gray Zhang
MD5是用来hash的,根本不存在唯一的原值。你MD5两次是没用的,不存在MD5一次的原值,当然更不存在MD5两次的原值,并且也不需要原值,只要两次MD5结果和你的一致就通过验证了。

 回复 引用 查看   
#27楼2008-08-15 23:40 | BoyLee      
碰撞不是解密.网上的解密都是查询数据库,MD5不可逆的
另外那个要老半天的,平时应用,应该没事吧,又不是开银行,hoho

 回复 引用 查看   
#28楼[楼主]2008-08-16 01:23 | 田嵩      
@Gray Zhang
只是2次MD5的话黑客可以截获2次MD5之后的值,然后模拟客户端直接向服务器发送这个值获得授权,这样就约等于使用明文了,虽然看不到明文但是目的达到了。

另外碰撞的解不出原文不过解出出来的可以和原文一样使用。所以我个人偏好SHA1。另外还有SHA256、384、512。。。

 回复 引用 查看   
#29楼2008-08-16 10:34 | Handy      
是不是可以这样呢?直接在客户端把用户名和密码还有验证码计算MD5值,返回服务端,这样本次有效,但是下次用中途截获的MD5值不是就没有用了吗?
防止传输中途资料被截获!
安全问题始终都是个问题@!

 回复 引用 查看   
#30楼[楼主]2008-08-16 11:46 | 田嵩      
@Handy
就是这个意思

 回复 引用 查看   
#31楼2008-08-16 15:33 | 簡簡單單..      
同意29楼..