转载 http://www.csharpwin.com/csharpspace/13412r9615.shtml

(一) 为什么要用哈希函数来加密密码

如果你需要保存密码(比如网站用户的密码),你要考虑如何保护这些密码数据,象下面那样直接将密码写入数据库中是极不安全的,因为任何可以打开数据库的人,都将可以直接看到这些密码。

解决的办法是将密码加密后再存储进数据库,比较常用的加密方法是使用哈希函数(Hash Function)。哈希函数的具体定义,大家可以在网上或者相关书籍中查阅到,简单地说,它的特性如下:

(1)原始密码经哈希函数计算后得到一个哈希值

(2)改变原始密码,哈希函数计算出的哈希值也会相应改变

(3) 同样的密码,哈希值也是相同的

(4) 哈希函数是单向、不可逆的。也就是说从哈希值,你无法推算出原始的密码是多少

有了哈希函数,我们就可以将密码的哈希值存储进数据库。用户登录网站的时候,我们可以检验用户输入密码的哈希值是否与数据库中的哈希值相同。

由于哈希函数是不可逆的,即使有人打开了数据库,也无法看到用户的密码是多少。

那么存储经过哈希函数加密后的密码是否就是安全的了呢?我们先来看一下几种常见的破解密码的方法。

(二) 几种常见的破解密码的方法

最简单、常见的破解方式当属字典破解(Dictionary Attack)和暴力破解(Brute Force Attack)方式。这两种方法说白了就是猜密码。

字典破解和暴力破解都是效率比较低的破解方式。如果你知道了数据库中密码的哈希值,你就可以采用一种更高效的破解方式,查表法(Lookup Tables)。还有一些方法,比如逆向查表法(Reverse Lookup Tables)、彩虹表(Rainbow Tables)等,都和查表法大同小异。现在我们来看一下查表法的原理。

查表法不像字典破解和暴力破解那样猜密码,它首先将一些比较常用的密码的哈希值算好,然后建立一张表,当然密码越多,这张表就越大。当你知道某个密码的哈希值时,你只需要在你建立好的表中查找该哈希值,如果找到了,你就知道对应的密码了。

(三) 为密码加盐(Salt)

从上面的查表法可以看出,即便是将原始密码加密后的哈希值存储在数据库中依然是不够安全的。那么有什么好的办法来解决这个问题呢?答案是加盐。

盐(Salt)是什么?就是一个随机生成的字符串。我们将盐与原始密码连接(concat)在一起(放在前面或后面都可以),然后将concat后的字符串加密。采用这种方式加密密码,查表法就不灵了(因为盐是随机生成的)。

(四) 在.NET中的实现

在.NET中,生成盐可以使用RNGCryptoServiceProvider类,当然也可以使用GUID。哈希函数的算法我们可以使用SHA(Secure Hash Algorithm)家族算法,当然哈希函数的算法有很多,比如你也可以采用MD5。这里顺便提一下,美国政府以前广泛采用SHA-1算法,在2005年被我国山东大学的王小云教授发现了安全漏洞,所以现在比较常用SHA-1加长的变种,比如SHA-256。在.NET中,可以使用SHA256Managed类。

下面来看一段代码演示如何在.NET中实现给密码加盐加密。加密后的密码保存在MySQL数据库中。

下面的代码演示如何注册一个新帐户。盐的生成可以使用新Guid,也可以使用RNGCryptoServiceProvider 类。将byte[]转换为string,可以使用Base64String,也可以使用下面的ToHexString方法。

protected void ButtonRegister_Click(object sender, EventArgs e) 

{ 

    string username = TextBoxUserName.Text; 

    string password = TextBoxPassword.Text; 

    // random salt 

    string salt = Guid.NewGuid().ToString();

    // random salt 

    // you can also use RNGCryptoServiceProvider class            

    //System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); 

    //byte[] saltBytes = new byte[36]; 

    //rng.GetBytes(saltBytes); 

    //string salt = Convert.ToBase64String(saltBytes); 

    //string salt = ToHexString(saltBytes); 

    byte[] passwordAndSaltBytes = System.Text.Encoding.UTF8.GetBytes(password + salt);            

    byte[] hashBytes = new System.Security.Cryptography.SHA256Managed().ComputeHash(passwordAndSaltBytes);

    string hashString = Convert.ToBase64String(hashBytes);

    // you can also use ToHexString to convert byte[] to string 

    //string hashString = ToHexString(hashBytes); 

    var db = new TestEntities(); 

    usercredential newRecord = usercredential.Createusercredential(username, hashString, salt); 

    db.usercredentials.AddObject(newRecord); 

    db.SaveChanges(); 

}

string ToHexString(byte[] bytes) 

{ 

    var hex = new StringBuilder(); 

    foreach (byte b in bytes) 

    { 

        hex.AppendFormat("{0:x2}", b); 

    } 

    return hex.ToString(); 

} 

下面的代码演示了如何检验登录用户的密码是否正确。首先检验用户名是否存在,如果存在,获得该用户的盐,然后用该盐和用户输入的密码来计算哈希值,并和数据库中的哈希值进行比较。

protected void ButtonSignIn_Click(object sender, EventArgs e) 

{ 

    string username = TextBoxUserName.Text; 

    string password = TextBoxPassword.Text;

    var db = new TestEntities(); 

    usercredential record = db.usercredentials.Where(x => ).FirstOrDefault(); 

    if (record == default(usercredential)) 

    { 

        throw new ApplicationException("invalid user name and password"); 

    }

    string salt = record.Salt; 

    byte[] passwordAndSaltBytes = System.Text.Encoding.UTF8.GetBytes(password + salt); 

    byte[] hashBytes = new System.Security.Cryptography.SHA256Managed().ComputeHash(passwordAndSaltBytes); 

    string hashString = Convert.ToBase64String(hashBytes);

    if (hashString == record.PasswordHash) 

    { 

        // user login successfully 

    } 

    else 

    { 

        throw new ApplicationException("invalid user name and password"); 

    } 

}

总结:单单使用哈希函数来为密码加密是不够的,需要为密码加盐来提高安全性,盐的长度不能过短,并且盐的产生应该是随机的。

转载 C#使用Salt + Hash来为密码加密的更多相关文章

  1. C# 使用Salt+Hash来为密码加密

    (一) 为什么要用哈希函数来加密密码 如果你需要保存密码(比如网站用户的密码),你要考虑如何保护这些密码数据,象下面那样直接将密码写入数据库中是极不安全的,因为任何可以打开数据库的人,都将可以直接看到 ...

  2. Web安全--使用Salt + Hash将密码加密后再存储进数据库

    转载原地址 http://www.bozhiyue.com/mianshiti/_net/2016/0728/314239.html (一) 为什么要用哈希函数来加密密码 如果你需要保存密码(比如网站 ...

  3. C# salt+hash 加密

    一.先明确几个基本概念 1.伪随机数:pseudo-random number generators ,简称为:PRNGs,是计算机利用一定的算法来产生的.伪随机数并不是假随机 数,这里的" ...

  4. 使用bcrypt进行用户密码加密的简单实现

    Bcrypt百度百科: bcrypt,是一个跨平台的文件加密工具.由它加密的文件可在所有支持的操作系统和处理器上进行转移.它的口令必须是8至56个字符,并将在内部被转化为448位的密钥. 除了对您的数 ...

  5. 使用mongoose和bcrypt实现用户密码加密

    前面的话 最近在做的个人项目中,需要对密码进行加密保存,对该操作的详细步骤记录如下 介绍 关于mongoose已经写过博客就不再赘述,下面主要介绍bcrypt bcrypt是一个由两个外国人根据Blo ...

  6. html5对密码加密

    今天找了几个关于对html5的密码加密的方法,仅供参考 1.base64加密:在页面中引入base64.js文件,调用方法为: <html> <head> <meta c ...

  7. C#:使用MD5对用户密码加密与解密

    C#中常涉及到对用户密码的加密于解密的算法,其中使用MD5加密是最常见的的实现方式.本文总结了通用的算法并结合了自己的一点小经验,分享给大家. 一.使用16位.32位.64位MD5方法对用户名加密 1 ...

  8. Maven-009-Nexus 用户密码加密(安全必须)

    信息数据大爆发的时代,我们关心什么?没错,数据安全!数据安全!数据安全!(重要事情说三遍,哈哈哈...) 之前我们存放在 maven settings.xml 文件中的 Nexus 私服用户密码都是明 ...

  9. Druid 数据库用户密码加密 代码实现

    druid-1.0.16.jar 阿里巴巴的开源数据连接池 jar包 明文密码+私钥(privateKey)加密=加密密码 加密密码+公钥(publicKey)解密=明文密码 程序代码如下: pack ...

随机推荐

  1. python-pickle模块使用实例

    以下代码主要实现的是用户登录,注册,密码验证,账户锁定,重置和修改密码等功能 import pickle #第一次运行请去掉下面一段代码的注释 ''' users_db = open("us ...

  2. iphone中 input圆角bug

    今天写了个简单的登录注册,在电脑手机(除了iphone)样式都没有问题,但在iphone中却出现了异常,提交的按钮变成圆角被背景渐变的效果,随后又测试两个iphone版都是一个样,断定应该是safar ...

  3. 微信企业号-JS-SDK图像接口

    使用JS-SDK需要进行四步  主要是步骤二和步骤三,步骤二需要配置,步骤三具体使用相关接口,这里以使用图像接口为例 php页面代码主要用来完成步骤二,也就是配置接口 public function ...

  4. 创建一个应用台程序,声明一个 int变量,并且初始化数组,通过while语句输出数组内的所有成员。

    ]{,,,,}; ; ) { Console.WriteLine("myNum[{0}]的值为{1}", s,myNum[s]); s++; } Console.ReadLine( ...

  5. Haproxy安装配置及日志输出问题

    简介: 软件负载均衡一般通过两种方式来实现:基于操作系统的软负载实现和基于第三方应用的软负载实现.LVS就是基于Linux操作系统实现的一种软负载,HAProxy就是开源的并且基于第三应用实现的软负载 ...

  6. ios 修正waring:Method override for the designated initializer of the superclass &#39;-init&#39; not found

    swift引入后,为了使oc和swift更相近,对oc的初始化方法也进行了修正,具体说明,见下面的链接,这个waring的最简单的修正方法是,到相应类的头文件中,去掉在自定义初始化方法后面的 NS_D ...

  7. Jmockit使用

    引用单元测试中mock的使用及mock神器jmockit实践中的java单元测试中各种Mock框架对比,就能明白JMockit有多么强大: JMockit是基于JavaSE5中的java.lang.i ...

  8. latch: cache buffers chains故障处理总结(转载)

    一大早就接到开发商的电话,说数据库的CPU使用率为100%,应用相应迟缓.急匆匆的赶到现场发现进行了基本的检查后发现是latch: cache buffers chains 作祟,处理过程还算顺利,当 ...

  9. RN组件之Switch与Picker

    一.Switch选择开关控件 1.该组件为Android/IOS通用的两种状态的开关组件 2.属性方法 (1)disabled bool:如果该值为true,用户就无法点击switch开关,默认为fa ...

  10. eclipse 下调整jdk和tomcat的jvm参数

    eclipse 下调试和运行,往往会出现调整java.lang.OutOfMemoryError: Java heap space  产生的原因我猜测是使用了maven,subversion,myla ...