建议114:MD5不再安全

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

MD5被广泛应用于密码验证和消息完整性验证。假设新注册一个用户,当注册用户的密码第一次被存储到数据库时,往往会将其转换为MD5值存储:

        static string GetMd5Hash(string input)
{
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
return BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(input))).Replace("-", "");
}
} static void Main(string[] args)
{
string source = "liming's key";
string hash = GetMd5Hash(source);
Console.WriteLine("保存密码原文:{0}的MD5值:{1}到数据库。",source,hash); Console.Read();
}

输出为:

保存密码原文:liming's key的MD5值:B222558FD330454B08878C61FD595121到数据库。

如果MD5值存储在数据库中,当用户登录时,只需要验证MD5就可以检查用户输入的密码是否正确。如下:

        static void Main(string[] args)
{
Console.WriteLine("请输入密码,按回车键结束……");
string source = Console.ReadLine();
if (VerifyMd5Hash(source, "B222558FD330454B08878C61FD595121"))
{
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) == ? true : false;
}

输出为:

请输入密码,按回车键结束……
liming's key
密码正确,准许登录系统。

处于隐私保护的目的,所以不直接存储密码。即便是一个银行系统,我们也不想让银行的后台管理人员看到我们的密码。而通过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 = ; i < ; i++)
{
if (VerifyMd5Hash(i.ToString(), "CF79AE6ADDBA60AD018347359BD144D2"))
{
key = i.ToString();
break;
}
}
watch.Stop();
Console.WriteLine("密码已破解,为:{0},耗时{1}毫秒。", key, watch.ElapsedMilliseconds);
}

输出为:

开始穷举法破解用户密码……
密码已破解,为:8888,耗时124毫秒。

可见,如果我们的密码过于简单,计算机甚至都不需要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 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(input))).Replace("-", "") + BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(hashKey))).Replace("-", "");
return BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(hashCode))).Replace("-", "");
}
}

在改进后的方法中,我们首先设计了一个足够复杂的密码hashKey,然后将它的MD5值和用户输入密码的MD5值相加,再求一次MD5值作为返回值。经过这个过程以后,密码的长度就够了,复杂度也够了,要想通过穷举法来得到真正的密码成本也就大大增加了。

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

编写高质量代码改善C#程序的157个建议——建议114:MD5不再安全的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  2. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  3. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  4. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  5. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  6. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  7. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  8. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

  9. 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量

    建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...

  10. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

随机推荐

  1. Memory leak by misusing Autofac

    Recently I’ve found out that we can easily cause a memory leaks in our .net application by improper ...

  2. OD 实验(七) - 对一个程序的破解和去广告

    程序: 这里有很多的动态链接库 双击运行程序 这个程序有次数限制 按钮也在隐藏处 主界面 退出程序,会弹出一个广告 目的: 让程序的使用次数不受限制,且没有显示次数的窗口 去除程序关闭时候的广告 逆向 ...

  3. python写个Hack Scan

    前言: 之前逛SAFEING极客社区的时候 发现一款黑市卖2000多的软件,后面下载了 打不开.发现config文件里面有些不错的东西.总结了一下 有了以下的脚本. 脚本用处: [1]探测CMS(不敢 ...

  4. Tkinter Dimensions

      Tkinter Dimensions: 各种长度,宽度,和其他部件的尺寸可以在许多不同的单位描述   各种长度,宽度,和其他部件的尺寸可以在许多不同的单位描述. 如果您设置了尺寸为整数,它被假定为 ...

  5. ubuntu 开机 输入密码 无法进入

    1.给笔记本装了ubuntu14.04.4, 发现开机到输入密码的环节之后,验证正确,然而无法进入桌面,一直在密码页循环. 2.网上找了好多方法,进入命令行(ctrl+alr+F1)登录,能登录进去: ...

  6. Python实践练习:strip()的正则表达式版本

    题目: 写一个函数,它接受一个字符串,做的事情和 strip()字符串方法一样.如果只传入了要去除的字符串,没有其他参数,那么就从该字符串首尾去除空白字符.否则,函数第二个参数指定的字符将从该字符串中 ...

  7. Service通信的两篇博文

    普通Service http://blog.csdn.net/liuhe688/article/details/6874378 AIDL通信 http://blog.csdn.net/liuhe688 ...

  8. html——网页高度

    确定浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条) var w=window.innerWidth || document.documentElement.clientWidth || doc ...

  9. golang 函数和方法

    由于自己是搞python开发的,所以在学习go时,当看到函数和方法时,顿时还是挺蒙的,因为在python中并没有明显的区别,但是在go中却是两个完全不同的东西.在官方的解释中,方法是包含了接收者的函数 ...

  10. Python OrderedDict使用

    一.最近最少使用实现: import collections class LRUDict(object): ''' 最近最少使用队列实现,最近使用的键值放后面 ''' def __init__(sel ...