一个简单的方式搞定密码的加盐哈希与验证

简介: 过去一段时间来, 众多的网站遭遇用户密码数据库泄露事件。层出不穷的类似事件对用户会造成巨大的影响,因为人们往往习惯在不同网站使用相同的密码,一家 “暴库”,全部遭殃。

过去一段时间来, 众多的网站遭遇用户密码数据库泄露事件。层出不穷的类似事件对用户会造成巨大的影响,因为人们往往习惯在不同网站使用相同的密码,一家 “暴库”,全部遭殃。

单向加密

一个简单的方案是将明文密码做单向哈希后存储。

单向哈希算法有一个特性,无法通过哈希后的摘要(digest) 恢复原始数据,这也是 “单向” 二字的来源,这一点和所有的加密算法都不同。常用的单向哈希算法包括 SHA-256, SHA-1, MD5 等。例如,对密码“passwordhunter” 进行 SHA-256 哈希后的摘要 (digest) 如下:

“bbed833d2c7805c4bf039b140bec7e7452125a04efa9e0b296395a9b95c2d44c”

可能是 “单向” 二字有误导性,也可能是上面那串数字唬人,不少人误以为这种方式很可靠, 其实不然。

单向哈希有两个特性:

1)从同一个密码进行单向哈希,得到的总是唯一确定的摘要

2)计算速度快。随着技术进步,尤其是显卡在高性能计算中的普及,一秒钟能够完成数十亿次单向哈希计算

结合上面两个特点,考虑到多数人所使用的密码为常见的组合,攻击者可以将所有密码的常见组合进行单向哈希,得到一个摘要组合, 然后与数据库中的摘要进行比对即可获得对应的密码。这个摘要组合也被称为 rainbow table(彩虹表)。

更糟糕的是,一个攻击者只要建立上述的rainbow table,可以匹配所有的密码数据库。仍然等同于一家 “暴库”,全部遭殃。

加盐哈希

将明文密码混入 “随机因素 “,然后进行单向哈希后存储,也就是所谓的”Salted Hash(加盐哈希)”。

这个方式相比上面的方案,最大的好处是针对每一个数据库中的密码,都需要建立一个完整的 rainbow table 进行匹配。 因为两个同样使用 “passwordhunter”作为密码的账户,在数据库中存储的摘要完全不同。

在 C# 中实现加盐哈希

早在2016年,MD5 作为哈希算法已经不可靠,可以人为制造碰撞,于是本文采用了 SHA256 作为哈希算法。同时在哈希前生成了一个 Guid 作为盐和哈希值拼接在一起:

    using System;
    using System.Security.Cryptography;
    using System.Text;

    public class PasswordHasher
    {
        public string HashPassword(string password)
        {
            var rnd = Guid.NewGuid().ToString("N").Substring(10);
            return BuildHash(rnd, password);
        }

        public bool CheckPassword(string password, string hash)
        {
            if (string.IsNullOrWhiteSpace(hash))
            {
                return false;
            }

            var items = hash.Split('|');
            if (items.Length != 2)
            {
                return false;
            }

            var rnd = items[0];
            return hash == BuildHash(rnd, password);
        }

        private string BuildHash(string rnd, string password)
        {
            var key = rnd + "|" + password.Trim();
            var hash = Hash(key);
            return rnd + "|" + hash;
        }

        private string Hash(string input)
        {
            using (var sha = new SHA256CryptoServiceProvider())
            {
                var bytes = Encoding.UTF8.GetBytes(input);
                bytes = sha.ComputeHash(bytes);
                return Convert.ToBase64String(bytes);
            }
        }
    }

生成加盐哈希值:

    //生成加盐哈希
    var hasher = new PasswordHasher();
    var pwd = hasher.HashPassword("123456");
    Console.WriteLine("加盐哈希值为:{0}",pwd);

校验密码是否匹配:

    //校验密码是否匹配
    var hasher = new PasswordHasher();
    var hash = "89455bb276f037799fea1d|1rcfw+tSKhpG7zuW7Sm6SuMgjafAwsMg76OlyFkXLm8=";
    var pwd = "123456";
    if (hasher.CheckPassword(pwd, hash))
    {
        Console.WriteLine("密码正确");
    }
    else
    {
        Console.WriteLine("密码不匹配");
    }
目录
相关文章
|
24天前
|
算法 安全 数据安全/隐私保护
散列值数据完整性验证
散列值数据完整性验证
43 11
|
28天前
|
存储 并行计算 算法
散列函数密码存储
散列函数密码存储
44 6
|
28天前
|
存储 算法 安全
散列函数数据完整性验证
散列函数数据完整性验证
40 5
|
2月前
|
存储 Java 数据库
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
这篇文章介绍了如何在Java中通过加盐和加密算法(如MD5和SHA)安全地存储密码,并提供了一个密码工具类PasswordUtils和密码编码类PasswordEncoder的实现示例。
73 10
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
|
4月前
|
存储 安全 算法
|
7月前
|
存储 算法 安全
密码哈希参考
OWASP组织针对密码存储提供了一个专题指引,本文针对里面的密码存储方法进行了翻译,并对密码存储(or 密码哈希)算法基于Go语言的crypto库实现做了一下的性能测试,并收集了对应算法的实现标准链接,方便后续进一步学习。
98 0
|
存储 安全 算法
2021年你还不会Shiro?----4.使用MD5+盐+hash散列进行密码加密
上一篇文章里介绍了使用自定义的Realm来实现数据的获取,不过,数据的获取依然不是来源于真实的数据库或者是nosql,只是包装了一个方法,假装从这个方法里获取了数据库中的用户信息,然后我们返回了一个SimpleAccount,这个对象携带了用户名与密码,当时我们是明文返回的密码。这样做很显然是不安全的,一旦数据来源被攻破,所有的用户信息都会被泄露。所以这里我们介绍下,常用的密码加密策略。
204 0
2021年你还不会Shiro?----4.使用MD5+盐+hash散列进行密码加密
|
Go 数据库 数据安全/隐私保护
Go实现随机加盐密码认证
Go实现随机加盐密码认证
319 0
|
数据库 数据安全/隐私保护
Shiro学习-密码的比对及密码的MD5加密(八)
Shiro学习-密码的比对及密码的MD5加密(八)
112 0
|
算法 数据安全/隐私保护
什么叫明文,什么叫密文、密码、密钥,为什么在数据库里不采用明文保存密码?
什么叫明文,什么叫密文、密码、密钥,为什么在数据库里不采用明文保存密码?
393 0