频道栏目
首页 > 资讯 > 系统安全 > 正文

安全随笔1:谨慎一次MD5值的可被穷举性

11-06-01        来源:[db:作者]  
收藏   我要投稿

MD5不再安全不是从算法本身而言。如果从可逆性角度出发, MD5值不存在被破解的可能性。MD5的算法公式如下:

R=H(S)

该公式指出:对于给定的一个源内容S,H可以将其映射为R。这里要注意几个特点。首先,S到R的映射是一种多对一的映射;其次,R作为目标内容,是一个无规律的定长的字符串;最后,映射H是一种压缩映射,即R的空间远远小于S。

MD5的算法特性使其无法存在一个逆过程,即:将R还原成为S,下面的公式不成立:

R=H-1(S)

正是基于以上的特点,MD5被广泛用于密码验证和消息体完整性验证。相信大家对于密码验证使用MD5算法都不陌生。假设新注册了一个用户,当注册用户的密码第一次被存储到数据库的时候,我们往往将其转换为MD5值存储:

        static void Main(string[] args)       

 {           

string source = "luminjis key";  

  string hash = GetMd5Hash(source);           

Console.WriteLine("保存密码原文:{0}的MD5值:{1}到数据库。", source, hash); 

       }       

 static string GetMd5Hash(string input)       

{           

using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())           

 {               

return BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(input))).Replace("-", "");           

 }        

}

以上代码输出:

保存密码原文:luminjis key的MD5值:D3A8E4D76A0AEF23B65D9F6D6BCB358F到数据库。有了MD5值存储在数据库中,在用户进行登录的时候,只要校验MD5就可以确保用户输入的是否是正确的密码了。如下:

        static void Main(string[] args)       

{           

Console.WriteLine("请输入密码,按回车键结束……");           

string source = Console.ReadLine();           

if (VerifyMd5Hash(source, "D3A8E4D76A0AEF23B65D9F6D6BCB358F"))           

 {               

Console.WriteLine("密码正确,准许登录系统。");           

 }           

else           

 {              

  Console.WriteLine("密码有误,拒绝登录。");           

}       

}       

static bool VerifyMd5Hash(string input, string hash)       

{           

string hashOfInput = GetMd5Hash(input);           

 StringComparer comparer = StringComparer.OrdinalIgnoreCase;           

return comparer.Compare(hashOfInput, hash) == 0 ? true : false;       

}

本段代码的输出为:

请输入密码,按回车键结束……luminjis key密码正确,准许登录系统。或许大家会问:为什么不直接存储密码,而使用MD5值呢?如果非要回答这个问题,我想更大程度上还是要从保护我们自己的隐私着想。即便是一个银行系统,我们也不想让银行的后台管理人员看到我们的密码。而通过MD5值,就可以确保这一点。通过验证MD5值,即保证了无人可以查看或破解我们的密码,也到达了密码验证的目的。虽然有人可能会质疑,MD5的算法不是一个多对一的映射吗?也就是说,很有可能存在一个另外的密码,求出来的MD5值和我的这个密码是一样的。但是,在实际应用场合中,这个概率会很小,小到可以忽略不计。

既然到目前为止,说到的都是MD5的好处,那么,为什么说MD5是不安全的呢?因为,这个世界上还有一个方法,叫做穷举法。鉴于使用我们的软件产品的用户大多数不是计算机专家,安全意识普遍比较薄弱,所以这类用户设置的密码很有可能是简单的数字组合。这个时候,穷举法就会派上很大的用处。以密码“8888”为例,测试下我们的穷举算法可以多长时间破解掉密码:

        static void Main(string[] args)       

 {           

 Console.WriteLine("开始穷举法破解用户密码……");           

 string key = string.Empty;           

 Stopwatch watch = new Stopwatch();           

watch.Start();           

 for (int i = 0; i < 9999; i++)           

 {               

 if (VerifyMd5Hash(i.ToString(), "CF79AE6ADDBA60AD018347359BD144D2"))               

 {                   

 key = i.ToString();                   

 break;              

  }           

 }           

 watch.Stop();          

  Console.WriteLine("密码已破解,为:{0},耗时{1}毫秒。", key, watch.ElapsedMilliseconds);      

  }

在上面的代码中,我们假设用户代码是“0”到“9999”的字符串,并在此范围内进行匹配。结果输出为:

开始穷举法破解用户密码……密码已破解,为:8888,耗时271毫秒。可见,如果我们的密码输入的过份简单,计算机甚至都不需要1秒时间就能完成暴力破解。当然,这种算法不是针对MD5的可逆破解,而是非常愚笨的穷举。但是,即便是这样,穷举带来的危害仍然是巨大的。现在,已经有很多的免费或商业的MD5字典库,存储了相当数量的字符串的MD5值,我们只要提交一个MD5值进去,立刻就可以得到它的原文,只要这个原文不是非常复杂。所以,从这个方面来说,MD5不再安全。

明白了这一点,我们就需要找一个方法来改进MD5求值。目前,最通用的做法是多次MD5值法。我们修改GetMd5Hash方法,如下:

        static string GetMd5Hash(string input)       

 {           

string hashKey = "Aa1@#$,.Klj+{>.45oP";           

 using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())           

{              

  string hashCode =

相关TAG标签
上一篇:安全随笔2:对称加密应用场景
下一篇:windows phone7.1中两个新增控件
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站