编写高质量代码改善C#程序的157个建议——建议114:MD5不再安全
建议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不再安全的更多相关文章
- 编写高质量代码改善C#程序的157个建议[1-3]
原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...
- 读书--编写高质量代码 改善C#程序的157个建议
最近读了陆敏技写的一本书<<编写高质量代码 改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...
- 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试
建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...
- 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本
建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...
- 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码
建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...
- 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣
建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...
- 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释
建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...
- 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释
建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...
- 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量
建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...
- 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法
建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...
随机推荐
- java后台读取配置文件中key与value -----demo2
/** * * @Title: getValue * @Description: TODO * @param key * @return import java.util.Properties; * ...
- SCI 美国《科学引文索引》(Science Citation Index, 简称 SCI )
科学引文索引 编辑锁定同义词SCI(科学引文索引)一般指科学引文索引 美国<科学引文索引>(Science Citation Index, 简称 SCI )于1957 年由美国科学信息 ...
- MySQL5.5安装与多实例
MySQL5.5编译安装 #1.2 cmake软件 cd /home/oldboy/tools/ tar xf cmake-2.8.8.tar.gz cd cmake-2.8.8 ./configur ...
- Quest *nix Xwindows
国内一般网站搜到的linux系统添加Xwindows都是无法完成的,至少我在Ct6.3上不行,也许是yum源配置不同问题 我举个站点大家自己上去看,本人就不多说了,多说也无益,. http://yao ...
- node全局变量process属性值(mac环境)
任意新建一个js文件,只需一行代码: console.dir(process); 保存该文件后执行,即可得到process变量的属性值列表: { title: 'node', version: 'v0 ...
- JQueryDOM节点操作
你一.JQueryDom节点操作 2.1查找节点 获取p节点 var $pDm=$("p"); 输出p节点的title属性 alert($pDm.attr("title& ...
- FTP服务器(SOCKET)返回异常 500 Command not understood
出现着这样的问题,一般是NLST中的参数包含特殊字符,如"\n",所以在发送SOCKET命令时,一定要检查命令参数的合法性.
- 拼接两个yuv合帧
http://blog.csdn.net/huahuahailang/article/details/9040847 /**************************************** ...
- a+b_1
题目截图: 思路: 直接输出即可. 代码如下: /* a+b */ #include <stdio.h> #include <string.h> #include <ma ...
- 【302】C# TreeView 控件使用说明
参考:C# 中treeview 树节点图标的动态加载,及选中时图标改变 参考:C# TreeView 控件的综合使用方法 参考:TreeView 类 参考:TreeNode 类 1. 添加根和子级 通 ...