tonyqus.cn

休养中..
随笔 - 202, 文章 - 1, 评论 - 1202, 引用 - 57
数据加载中……

老调重弹——你存储的密码做Hash了吗?

看了标题,你马上会明白我这篇文章要讲什么——密码的Hash化,虽然这并不是什么新技术,也不是高端技术,但它确实很有意义。当然如果仅仅因为它有意义还不足以让我写这篇文章。有些人会觉得不就是密码Hash嘛,没有什么必要,还会影响网站的处理速度,如果你是这些人中的一员,请听我说两个真实的故事。

故事1
某黑客通过一些技术手段进入了一个刚刚起步的网站(至于用什么方法大家就不要多问了,再说与这篇文章关系不大),这个网站的安全问题很严重,严重到可以拿到所有用户的用户名、邮箱、网站密码。大家知道,很多人不喜欢记太多密码,他们在任何网站使用的永远是同一个密码。好了,问题出来了!这里面有大量的gmail、msn账户,也就是说知道邮箱,知道密码,我们不但能进入这个人的电子邮箱,还能进入googletalk或msn这样的及时聊天系统,从而获得更多的私人信息和关系网信息,甚至能冒用这个人的身份进行诈骗,还好这个黑客并没有恶意,并没有采取进一步的行动,否则后果不堪设想。

这个故事告诉我们在不同的网站、邮箱要使用不同的密码,当然要选择自己好记些的,但千万不要为了图方便而都用一样的密码,这是很危险的!特别是涉及金融、银行方面的网站更要使用高强度密码(有数字、大小写字母、下划线等组成),这样可以防止一些人用字典进行密码破解。从另一个角度看,这个故事还告诉我们,作为网站的开发者你必须时刻记住一点,在任何时候都不应该把机密数据用明文保存或传递,数据从进入系统那一刻开始网站就有义务保证数据的安全性,所以必须作相应的安全处理。对于密码,我们应该对密码做Hash,大家应该知道一个字符串无论何时做Hash,出来的结果是一样的,虽然从理论上讲会出现不同的字符串产生相同的Hash序列的情况,但是这种概率很低,基本上是中彩票的概率,这也是为什么要用Hash逆推出原文来几乎是不可能的,我们可以认为这种方法是安全的。

故事2
早上我在公交车上听到几句电话对话
甲:你密码忘记了?
....
甲:这个没关系,我帮你去问问IT部,他们知道密码是多少?
....

可能乍一看,这段对话很正常,没有什么特别的,但是我们可以分析一下其中的含义。密码忘了我们第一个想到的是什么——要回密码,但这能够实现吗?对于一个公司内部而言,这种密码获取还相对简单,毕竟大家可以方便地证明自己的身份,所以从业务上来讲似乎拿回密码一点问题都没有,但实际上,技术上不允许我们这么做。我们刚才说到过Hash是不可逆的,如果一个网管告诉你他可以帮你拿回原来的密码,这说明什么?说明密码很有可能是用明文存储的,这在很多情况下是很危险的,管理员可以利用自己的职权,获得一些人的密码,然后进入那些人的私人邮箱(非公司邮箱)盗取信息。即使有些密码是加密存储的,如果它是可逆的那也是不安全的,只要有加密后的字符串,且知道加密算法和密钥,也能轻易获得原密码,这同样是很危险的,当然相对而言这种方法要难许多、不是每个人都能做到的,但在第一个故事中我们看到如果某个黑客进入了这样的系统,仍然有办法获得原密码,毕竟黑客的技术水准要高出许多。从这一点我们应该意识到加密的密文必须不可逆,否则会带来进一步的信息泄漏。

好了,通过上面两个故事,我想大家应该对密码Hash的必要性比较认同了,希望以后在写code或者做架构设计的时候一定要把这个它考虑进去。从技术角度讲,我们只能为用户重置密码,但不能告诉用户原密码是什么,这一点live.com就做得很好,如果哪个网站可以拿回原密码,说明他不够安全,建议马上改密码!用一个和你的邮箱不一样的密码,特别是注册这个网站时使用的那个邮箱。

下面我顺便讲讲.NET下如何实现密码Hash化。有人说,Hash可以用System.Security.Cryptography命名空间下面的加密类来实现,对,说得没错,我们的确可以这么做,但这似乎还是有些麻烦~~(我比较懒,呵呵)其实呢,.NET提供了一个专门用于做Password Hashing的方法,这在.NET 1.1中就有了,定义如下:

public static string HashPasswordForStoringInConfigFile (
    
string password,
    
string passwordFormat
)

第一个参数password就是密码,而第二个参数则是要使用的Hash算法,这个值只能是FormsAuthPasswordFormat枚举的成员(位于System.Web.Configuration下),不过不清楚为什么不直接传枚举类型。FormsAuthPasswordFormat有三个枚举成员,它们是Clear、MD5、SHA1,其中的Clear就是不加密,直接用明文的意思。

具体的例子MSDN上有,我就不抄了,大家可以参考:http://msdn2.microsoft.com/en-us/library/system.web.security.formsauthentication.hashpasswordforstoringinconfigfile.aspx

===========================更新2007.12.19====================================
感谢兄弟们提宝贵意见,加了一个基于Salt的密码Hash实现,代码如下:
    public class PasswordHelper
    
{
        
public static string CreateSalt(int size)
        
{
            
//Generate a cryptographic random number.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            
byte[] buff = new byte[size];
            rng.GetBytes(buff);

            
// Return a Base64 string representation of the random number.
            return Convert.ToBase64String(buff);
        }


        
public static string CreatePasswordHash(string pwd, string salt)
        
{
            
string saltAndPwd = String.Concat(pwd, salt);
            
string hashedPwd =
             FormsAuthentication.HashPasswordForStoringInConfigFile(
             saltAndPwd, 
"sha1");

            
return hashedPwd;
        }


        
public static bool PasswordMatch(string current,string salt,string savedPasswordHash)
        
{
            
string currentPasswordHash=CreatePasswordHash(current, salt);
            
return (currentPasswordHash == savedPasswordHash);
        }

    }

大家有意见请继续踊跃发言:)

posted on 2007-12-18 18:06 Tony Qu 阅读(3138) 评论(27)  编辑 收藏 所属分类: .NET 1.1 技术其他.NET 2.0 技术其他Web相关技术

评论

#1楼    回复  引用  查看    

group by一下md5后的密码,可以发现很多密码的数量很高,说明大家都喜欢用这个密码,呵呵,HASH后也不怎么安全阿
2007-12-18 18:12 | lovecherry      

#2楼 [楼主]   回复  引用  查看    

但是充其量黑客只能破解这个网站,这个用户的邮箱和其他账号他破不了,因为不知道原密码
2007-12-18 18:14 | Tony Qu      

#3楼    回复  引用  查看    

虽然从理论上讲会出现不同的字符串产生相同的Hash序列的情况,但是这种概率很低,基本上是中彩票的概率

--------------------
这个不对,Hash是摘要算法,明文的空间是无穷大,而Hash值的空间是固定的,也就是Hash的个数值是固定的,比如任何明文,md5做完后都是16个字节,无论明文有多长,以有限对无限,所以每个Hash值都对应无数个明文值。所以不同字符串产生相同hash序列的情况是一定的。
应该说两段有意义,并且意义相近的字符串,产生相同hash值得概率是比较低的。
2007-12-18 18:31 | ocean      

#4楼 [楼主]   回复  引用  查看    

@ocean:
有道理~
2007-12-18 18:35 | Tony Qu      

#5楼    回复  引用  查看    

喜欢用简单密码的还是很容易被解的.
http://www.cmd5.com/
2007-12-18 18:36 | 回头重来      

#6楼    回复  引用  查看    

要通过加Salt值之后进行Hash,这样可以避免两个人密码相同时产生相同的散列值
2007-12-18 18:47 | Anders Liu      

#7楼    回复  引用  查看    

现在MD5-16/32的8位以下密码已经被破的差不多了,所以取10位甚至16位以上的混合密码+Hash才是比较安全的选择。有些网站你输入8个大小写,已经算你最高安全级别了,其实是误导人。
但这毕竟只是“防君子,不妨有耐心的小人”的方法,被暴力破解的概率永远>0,啥时候全世界都通用指纹或者眼角膜之类的识别就好了^_^(不过恐怕那时候我要带着手套上街了,hoho说笑了)
2007-12-18 19:11 | SZW      

#8楼    回复  引用  查看    

想问一下,即使MD5加密了。别人不是照样可以找出原密码吗。。
2007-12-18 20:13 | 静旅      

#9楼    回复  引用  查看    

.NET Pet Shop 4.0
它密码怎么加密,知道的人说说,谢谢拉
2007-12-18 20:14 | 静旅      

#10楼    回复  引用  查看    

再Salt一下就没问题了
2007-12-18 20:54 | 远航      

#11楼    回复  引用  查看    

@SZW
加上Salt 就没问题了

#12楼    回复  引用  查看    

建议把自己的需要的密码分开对待,不要用一样的!
2007-12-18 20:59 | Enzo      

#13楼    回复  引用  查看    

@SZW
你说的那种 破解实际上就是把已知的字符串的 Md5 储存起来,然后查询,只要加个Salt 那种方法就无效了

#14楼    回复  引用  查看    

@有物先天下 混成不知名
是的,所以才会有一个位数的限制,问题是在不加盐=>加盐的过度中,空子还是很大的。我想那些从网上下源码使用的人修改代码去加盐的可能1%都不到,而那99%的人,只要随便下个同样的源码,看一下salt插到哪儿了,问题就明朗很多了。
此外暴力破解对于本身就短的密码来说,加多少Salt都是不安全的。
2007-12-18 21:41 | SZW      

#15楼    回复  引用  查看    

@SZW
密码比指纹眼膜要安全的多,密码能改,后面两个一旦丢失你就完了。
2007-12-18 21:46 | Jeffrey Zhao      

#16楼 [楼主]   回复  引用  查看    

好像大家没搞清楚,王晓云破解的方法是能够产生相同的hash,但是推倒不出原来的密码~~只不过能够找到一个能够生成相同hash的字符串,这个与破解原密码还是有距离的~~只能算假破解
2007-12-18 22:29 | Tony Qu      

#17楼    回复  引用  查看    

@Tony Qu
SZW 说的不是 王晓云的破解方法,而是穷举,比如先把6位以内的密码对应的结果算出来存储起来,然后用MD5后的结果做索引,这样除开最开始的计算时间外,查找的时间会很短.空间换时间而已.

@SZW
如果 Salt 的位数是8位 那么即使加4位的密码也是12位,而每个用户的 Salt 不同,那么即使在知道 Salt 的情况下要破解也只有临时去计算MD5,而不能先计算好然后查询的方式.
如果不加 Salt 那是程序员的问题不在考虑之内.
先计算好然后查询和临时Md5暴力破时间成本相差很大.
没有不能破解的密码,只有成本是否能承受.

#18楼    回复  引用  查看    

即使所有用户的 Salt 都一样,只要不是和别人的程序用同一个 Salt ,那么只要不是你的用户数据非常多,或者非常重要,一般来说 Hacker 会放弃,而另外找一个站的数据.

#19楼    回复  引用  查看    

md5是Hash,所以属于摘要算法,而不是加密算法,所以无法破解出明文,因为对应的明文有无数多个,说哪一个都是正确的。这就像你对一篇文章做了摘要,那么你通过摘要无法还原文章一样,因为在摘要就是获取原文最有特征的信息,而抛弃一切其它信息,既然抛弃了很多信息,所以无法复原原文。
王晓云能够在比较短的时间内找到一个碰撞,这就比通过穷举来获得碰撞所用的时间小多了。
Hash算法已经非常出现很久了,所以这个世界上有很多md5的数据库,就是明文-〉Hash值对应值,这种数据库不断地搜集这种对应值,数量巨大,所以很多时候黑客只要把hash值和数据库匹配一下,就可以得到一个碰撞的明文,速度非常快。
2007-12-19 00:31 | ocean      

#20楼    回复  引用  查看    

@ocean
对付 md5数据库的最好方法就是 Salt

#21楼    回复  引用  查看    

@有物先天下 混成不知名
我也比较信赖Salt,用不用和改不改salt确实是程序员的问题,但是现在至少国内大部分下载的网站都没有用是现实问题。破解的是最现实的密码。
毕竟通常情况下同一段程序对于Salt的插入点还是有规律可循的。
我之前说的“防君子,不妨有耐心的小人”也就是针对这篇文章所说的单纯MD5而言的。目前看来Salt确实是最好的办法。

@Jeffrey Zhao
我那句话就是说笑的,只是在我本子上几年用下来觉得挺爽,憧憬一下,不用当真:)我还不想真的带着手套上街呢:)
2007-12-19 06:00 | SZW      

#22楼    回复  引用  查看    

我一般的做法是,先将密码hash,然后密码和用户名一起hash
2007-12-19 08:52 | t-mac.NET      

#23楼    回复  引用  查看    

以前1.1将用户的密码简单的哈希一下保存,结果到2.0就升级不上来了。被客户骂死了。
2007-12-19 09:52 | Kain      

#24楼    回复  引用  查看    

@Kain
--引用--------------------------------------------------
Kain: 以前1.1将用户的密码简单的哈希一下保存,结果到2.0就升级不上来了。被客户骂死了。
--------------------------------------------------------
以前碰到过这种情况,只不过是不同系统间的切换,这时候效率最高的办法就是登陆时候提示让用户使用“找回密码(其实也找不回)”功能重新设一下了
2007-12-19 12:04 | SZW      

#25楼    回复  引用  查看    

不错啊
2007-12-19 14:47 | Zhuang miao      

#26楼    回复  引用  查看    

好,我这儿几个平台都没有考虑那么多,抽时间补上!
2007-12-20 09:30 | 辉郎      

#27楼    回复  引用  查看    

MD5破的很多。
2007-12-20 17:25 | 巫云