2011年12月26日星期一

密码已无家可归

原文链接http://genghis-yang.tk/?p=91

今年的冬至是整个互联网的冬至,随着CSDN上600万用户密码泄漏,紧接着就是人人、多玩、7k7k、天涯……悲情的我在这些网站上都注册过,真要改密码非得改到我手软。最后一想就CSDN上还有点积分,其他就不改了吧。看报道说CSDN和天涯等网站都已经报案了,真不知是哪个黑客这么牛,真心希望他不会被逮到。这不是反语,仅是真心的愿望。所有谴责黑客的人,都是些不懂密码学不懂互联网的,作为一个通信专业的研究生,我觉得我有理由这么说。CSDN、天涯等网站为了降低那么一点成本,就置用户利益于不顾,它们竟然还有脸报案,真是让人愤慨。

我说这些不是空穴来风,任何一个了解互联网通信,了解密码学的人都能够看出来。下面我从技术的角度来分析分析,为什么我们的密码会被盗取。

首先我们要知道,密码都出现在哪儿?密码可能出现在3个地方:1.你的电脑上(包括你在浏览器里输入密码和在笔记本里记录密码);2.网站服务器上;3.你的电脑和网站服务器之间,用来连接两端的网络中。如果非要有第4个地方,那就是黑客的电脑上。

其次我们看看黑客可能从哪些渠道获得我们的密码,碰巧了也是3个:1.入侵你的电脑,偷窥你的输入;2.入侵服务器网站;3.在你的电脑和网站服务器之间某个节点上截取你发送给服务器的密码。

如果将上面一对照,你会发现凡是密码出现的地方都会有泄密的可能。那么我们的密码岂不是毫无安全性可言?当然不是这样。黑客可不是城管不是国保,要入侵安装好更新补丁的个人电脑几乎不可能(乱下东西中毒的不在此列)。网络中你电脑和服务器之间的转发节点大都为硬件,如果不亲手碰到黑客也无法控制(电信联通的人可以),无法用来截取你的密码。唯一可能泄漏密码的就是服务器了,因为服务器运行大量的互联网程序,漏洞在所难免。而这一次各大网站密码泄漏就都是这个途径。

服务器被入侵就会泄漏用户密码吗?我想要告诉大家的是:即使服务器被入侵,密码也绝对不会泄漏!因为用户密码在服务器上根本看不到。比方说我的密码是“0123456789”,在服务器上存的却是“87ACEC17CD9DCD20A716CC2CF67417B71C8A7016”,如果密码是“ppnn13%dkstFeb.1st”,服务器存的就是“3FB8F80558CC39B09225122428947D07C82DF4C8”。黑客即使入侵服务器,看到一堆类似于“87ACEC17CD9DCD20A716CC2CF67417B71C8A7016”这样的密码也是无可奈何的。

为何我们的密码会被保存成那个怪样子?这就要涉及到数学和密码学中的一个概念:单向散列函数。对于这个概念足够写几本书,这里我只简要介绍。这个函数跟我们数学中的函数是一样的,它以我们的密码为输入,输出就是那一串怪模怪样的东西,只不过这个函数是不可逆的。也就是说我们知道输入可以得到输出,但如果只知道输出是无法通过数学方法得到输入的。所以即使黑客看到“87ACEC17CD9DCD20A716CC2CF67417B71C8A7016”也无法推算出我的密码是“0123456789”。

有了单项散列函数,我们的密码基本上就安全了,如果不懂密码学看到这儿应该还是云里雾里的。下面来看看单向散列函数是怎么起作用的。对于稍大型的网站,当我们注册时,我们在浏览器输入的密码(用A代替)都会通过一个叫SSL的东西加密成X,(SSL是用来防止密码在传输过程中被黑客截取,也就是防止前面说的途径3)加密之后再通过网络传给服务器,然后服务器再用得到的X进行SSL解密得到我们的密码A。接下来服务器不会保存我们的密码,而是对密码做单向散列函数,得到那么一个怪字符串AA,然后把这个字串AA存下来。下一次我们要登录时,我们输入的密码再一次通过SSL加密后发给服务器,服务器再通过SSL解密,再对密码做单向散列函数,又得到一个怪字符串B,服务器拿新生成的字符串B与保存的字符串AA进行比较,如果相同说明两次输入一致,如果不同就说明你密码输错了。这样一来我们的密码只是在服务器内存里短暂停留,根本没在服务器上保存。那么黑客如果入侵服务器获得AA呢?他只能无奈。因为服务器会对任何输入都做单向散列函数,如果他把AA当密码输入,就会对AA进行单向散列。可以想象同一个函数对不同的输入A和AA将得到的不同的值,输入A得到AA,输入AA就得到其他值Y,之后服务器一比较,Y和AA根本不想等嘛,黑客的登录也就失败了。

上面的方法对大多数网站来说已经能够很好的满足安全性需要了。但一些支付类网站,例如网银、淘宝等,因为其特殊性需要更好的保护密码。因此它们的密码流程与上面的描述又略有不同。例如支付宝会给你电脑装一个“支付宝安全控件”,一些网银也会装类似的控件,这些控件里就包含一个产生单向散列函数值的程序。这样一来,我们输入的密码A在我们自己的电脑上就变成了一串怪字符串AA,然后再通过SSL加密成XX发给服务器,服务器通过SSL解密得到AA,再进行单向散列函数得到AAA,然后把AAA保存起来。下一次登录时输入的密码经过同样的流程得到C,然后拿C和AAA比较。这样的方法,密码在整个网络中根本没出现过,除非你输密码时被人看见否则无法泄漏。

上面介绍的这些方法都很成熟了,黑客即使本领再大也不能违反数学定律。但为什么我们的密码还是被泄露了呢?因为这些网站偷了懒。上面这两种方法都需要在每次登录时在服务器上进行一次单向散列函数,单向散列函数的运算相对比较复杂,需要较多的运算时间,而大型网站每一秒都可能有人登录,大量的登录请求意味着需要进行大量单向散列函数运算,需要增加服务器成本。因此这些网站,如CSDN、人人网、天涯都把服务器上进行的这个步骤给省略了,仅仅将SSL解密后的密码A直接保存成A。黑客一入侵看到的就是A,自然毫无阻拦的完成了密码盗取。而淘宝虽然使用安全控件把你的密码变成AA,但如果服务器端不再次进行单向散列函数,直接保存AA的话,黑客可以伪造一个“伪支付宝安全控件”把他看到的AA发给服务器,服务器就会允许登录。前段时间我的支付宝密码就被盗了,我怀疑就是这个原因。

像我这样所有网站同一个注册名同一个密码,这次可是栽了,一个被盗,全就被盗了。心里怨恨也没用,毕竟不能指望中国这些无良网站,要安全还得靠自己。我的打算是:自己造个函数,根据每个网站的域名生成一个密码,以后把函数记住就行了,再被盗也只是某一个网站了。

2 条评论:

  1. Warez like Password Manager might meet what you wanna protect your customized password/passphrase ;-)

    回复删除
  2. Yeap, I am using Lastpass now.

    回复删除