Hashed password with salted value——利用salt对密码进行散列
来源:互联网 发布:星火网络电视 编辑:程序博客网 时间:2024/05/22 08:16
在没有学习web安全密码学部分的时候,我自己全部的密码都是同一个,而且是7位数字组成的。还好我本身没有什么财产好损失,不过都不会再犯这种愚蠢错误了。
我们为什么需要对密码进行hash化,又为什么要在hash化之前给它加一个随机值?我想从一个例子分析起:我看过一个黑客的文章,讲的是他通过一些技术手段进入了一个刚刚起步的网站,他表示这个网站的安全问题非常严重,严重到可以拿到所有用户的用户名,邮箱和密码。大家可能都有这样的感受,就是不爱记忆太多的密码,所以大部分的网站或者应用都用了同一个密码!这样,黑客不仅可以进入邮箱,而且可以进入QQ、MSN等及时聊天系统,从而获得更多的私人关系和关心网信息,这也就是为什么会有那么多利用QQ进行诈骗亲朋好友的案例。还好写这个文章的黑客没有恶意,只是指出了这个网站的问题,否则后果不堪设想(由此看来大部分黑客的职业操守还是很高的o(∩_∩)o )。
所以这个故事告诉我们,尽量不要用相同的密码,特别是重要的如银行账户之类的,一定要谨慎。那么大家现在都知道对密码进行hash,比如MD5之类的可以比较有效的防止被破译。但是事实真的是这样吗?
如果直接对密码进行hash,那么黑客可以对一个已知密码进行散列,然后通过对比散列值得到某用户的密码。换句话说,虽然黑客不能取得某特定用户的密码,但他可以知道使用特定密码的用户有哪些!这时,我们可以通过加salt来从一定程度上解决这个问题。什么是salt,顾名思义salt这个“佐料”也就是在对密码进行hash时,添加的一个随机数。其基本想法是这样的——当用户首次提供密码时(通常是注册时),由系统自动往这个密码里撒一些“佐料”,然后再散列。而当用户登录时,系统为用户提供的代码撒上同样的“佐料”,然后散列,再比较散列值,以确定密码是否正确。因为salt值是系统随机生成的,即使两个用户用了相同的密码,他们的hash值也不一样,黑客找出密码的几率大大减小了(必须是密码和自己生成的散列值都跟用户相同,这个概率很低了)。
下面讨论一下用户注册的过程:
1)用户提供密码(以及其他用户信息);2)系统为用户生成Salt值;
3)系统将Salt值和用户密码连接到一起;4)对连接后的值进行散列,得到Hash值;
5)将Hash值和Salt值分别放到数据库中。
当用户登录时,相应的过程是:
1)用户提供用户名和密码;
2)系统通过用户名找到与之对应的Hash值和Salt值;
3)系统将Salt值和用户提供的密码连接到一起;
4)对连接后的值进行散列,得到Hash'(注意有个“撇”);
5)比较Hash和Hash'是否相等,相等则表示密码正确,否则表示密码错误。
感觉说的比较清楚了,也是结合了网上一些资料和自己的体会写出来的。下面用网上一篇博客里的代码详细的分析一下对密码执行散列和salt的方法。正好在学习c#也是对自己的一个提升。
原文链接http://www.cnblogs.com/esshs/archive/2005/03/29/127998.html
- <span style="font-size:16px;">using System;
- using System.IO;
- using System.Text;
- using System.Security.Cryptography;
- namespace BookStore.Common
- {
- /// <summary>
- /// Credentials 的摘要说明。
- /// 原理:
- /// 对密码执行散列运算
- /// 若要避免以明文形式存储密码,一种常见的安全做法是对密码执行散列运算。如以下代码所示,使用 System.Security.Cryptography 命名空间(它实现 160 位 SHA-1 标准)对密码进行散列运算。有关更多信息,请参见 SHA1 成员。
- /// 对散列执行 Salt 运算
- /// 虽然对密码执行散列运算的一个好的开端,但若要增加免受潜在攻击的安全性,则可以对密码散列执行 Salt 运算。Salt 就是在已执行散列运算的密码中插入的一个随机数字。这一策略有助于阻止潜在的攻击者利用预先计算的字典攻击。字典攻击是攻击者使用密钥的所有可能组合来破解密码的攻击。当您使用 Salt 值使散列运算进一步随机化后,攻击者将需要为每个 Salt 值创建一个字典,这将使攻击变得非常复杂且成本极高。
- /// Salt 值随散列存储在一起,并且未经过加密。所存储的 Salt 值可以在随后用于密码验证。
- /// </summary>
- public class Credentials
- {
- private static string key = "!48%0d-F=cj>,s&2"; //密钥(增加密码复杂度,好像比较多余)
- private const int saltLength = 4; //定义salt值的长度
- /// <summary>
- /// 对密码进行Hash 和 Salt
- /// </summary>
- /// <param name="Password">用户输入的密码</param>
- /// <returns></returns>
- public static byte[] HashAndSalt(string Password)
- {
- return CreateDbPassword(HashPassword(Password));
- }
- /// <summary>
- /// 对用户输入的密码加上密钥key后进行SHA1散列
- /// </summary>
- /// <param name="Password">用户输入的密码</param>
- /// <returns>返回 160 位 SHA-1 散列后的的byte[](160位对应20个字节)</returns>
- private static byte[] HashPassword( string Password )
- {
- //创建SHA1的对象实例sha1
- SHA1 sha1 = SHA1.Create();
- //计算输入数据的哈希值
- return sha1.ComputeHash( Encoding.Unicode.GetBytes( Password + key ) );
- }
- /// <summary>
- /// 比较数据库中的密码和所输入的密码是否相同
- /// </summary>
- /// <param name="storedPassword">数据库中的密码</param>
- /// <param name="Password">用户输入的密码</param>
- /// <returns>true:相等/false:不等</returns>
- public static bool ComparePasswords(byte[] storedPassword, string Password)
- {
- //首先将用户输入的密码进行Hash散列
- byte[] hashedPassword = HashPassword(Password);
- if (storedPassword == null || hashedPassword == null || hashedPassword.Length != storedPassword.Length - saltLength)
- {
- return false;
- }
- //获取数据库中的密码的salt 值,数据库中的密码的后4个字节为salt 值
- byte[] saltValue = new byte[saltLength];
- int saltOffset = storedPassword.Length - saltLength;
- for (int i = 0; i < saltLength; i++){
- saltValue[i] = storedPassword[saltOffset + i];
- }
- //用户输入的密码用户输入的密码加上salt 值,进行salt
- byte[] saltedPassword = CreateSaltedPassword(saltValue, hashedPassword);
- //比较数据库中的密码和经过salt的用户输入密码是否相等
- return CompareByteArray(storedPassword, saltedPassword);
- }
- /// <summary>
- /// 比较两个ByteArray,看是否相等
- /// </summary>
- /// <param name="array1"></param>
- /// <param name="array2"></param>
- /// <returns>true:相等/false:不等</returns>
- private static bool CompareByteArray(byte[] array1, byte[] array2)
- {
- if (array1.Length != array2.Length)
- {
- return false;
- }
- for (int i = 0; i < array1.Length; i++)
- {
- if (array1[i] != array2[i])
- {
- return false;
- }
- }
- return true;
- }
- /// <summary>
- /// 对要存储的密码进行salt运算
- /// </summary>
- /// <param name="unsaltedPassword">没有进行过salt运算的hash散列密码</param>
- /// <returns>经过salt的密码(经过salt的密码长度为:20+4=24,存储密码的字段为Binary(24))</returns>
- private static byte[] CreateDbPassword(byte[] unsaltedPassword)
- {
- //获得 salt 值
- byte[] saltValue = new byte[saltLength];
- RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
- rng.GetBytes(saltValue);
- return CreateSaltedPassword(saltValue, unsaltedPassword);
- }
- /// <summary>
- /// 创建一个经过salt的密码
- /// </summary>
- /// <param name="saltValue">salt 值</param>
- /// <param name="unsaltedPassword">没有进行过salt运算的hash散列密码</param>
- /// <returns>经过salt的密码</returns>
- private static byte[] CreateSaltedPassword(byte[] saltValue, byte[] unsaltedPassword)
- {
- //将salt值数组添加到hash散列数组后拼接成rawSalted数组中
- byte[] rawSalted = new byte[unsaltedPassword.Length + saltValue.Length];
- unsaltedPassword.CopyTo(rawSalted,0);
- saltValue.CopyTo(rawSalted,unsaltedPassword.Length);
- //将合并后的rawSalted数组再进行SHA1散列的到saltedPassword数组(长度为20字节)
- SHA1 sha1 = SHA1.Create();
- byte[] saltedPassword = sha1.ComputeHash(rawSalted);
- //将salt值数组在添加到saltedPassword数组后拼接成dbPassword数组(长度为24字节)
- byte[] dbPassword = new byte[saltedPassword.Length + saltValue.Length];
- saltedPassword.CopyTo(dbPassword,0);
- saltValue.CopyTo(dbPassword,saltedPassword.Length);
- return dbPassword;
- }
- }
- }</span>
- Hashed password with salted value——利用salt对密码进行散列
- 详解对密码执行散列和 salt 运算方法
- 详解对密码执行散列和salt运算方法
- 利用Python 破解类unix系统 /etc/shadow 文件hashed password
- 加salt的散列方法(多用于密码存储)
- DATASTAGE——Hashed file stage使用
- DATASTAGE——Hashed file stage使用
- 加盐哈希-Salted Password Hashing
- Salted Password Hashing - Doing it Right
- password: salt + hash
- Creamed Spinach with Montreal Salted Herbs
- 利用散列函数进行字符串匹配
- Cas Password + Salt修改说明
- (key,value)对value进行排序
- Map对value进行排序
- 密码加salt
- mapreduce 利用InverseMapper.class对key,value进行 交换实现词频排序
- mapreduce 利用InverseMapper.class对key,value进行 交换实现词频排序 .
- 对于linux下system()函数的深度理解(整理)
- SSH框架搭建步骤(转)
- SQL日期函数
- Delphi for iOS开发指南(16):在iOS客户端应用程序中连接企业级数据库
- C#中winform中区分Close()和点击窗体右上角关闭按钮来关闭窗体
- Hashed password with salted value——利用salt对密码进行散列
- 使用JDK自带jvisualvm监控tomcat
- Delphi For iOS开发指南(17):让应用程序禁止竖屏(也就是只显示横屏)
- Dirichlet distribution的另一种理解,对应的如何解释dirichlet process
- CRM上线之路 走上了CRM实施顾问-第29天上班 -第七周
- commandline music player
- LeetCode —— Valid Number
- socket编程学习第一天
- 提高Office2010等高版的启动速度文章链接收集-Office2010打开慢速度怎么办?