MD5 or Bcrypt?
MD5 or Bcrypt?
摘要
首先是一个错误的认识观念问题,很多人觉得MD5是一个加密算法。不然,他实则是一种
摘要算法,也可以叫哈希函数。他的作用是将目标文本转换成具有相同长度、不可逆的杂凑字符串。而加密算法和他恰恰相反,是将目标转换成具有不同长度、可逆的密文。
MD5简介
一般来说由于摘要算法他的单向运算,具有一定的不可逆性也就是说信息无法被还原了,所以成为加密算法中的一个构成部分。MD5他的具体原理可以看B站这个up的容易理解 传送门
但在现在看来任何场景下都最好不要使用MD5,因为他不够安全,跟存储明文没啥两样。可以使用诸如SHA256、SHA512这类其他的摘要算法来替代。MD5的不够安全从下面说起:
MD5的不安全性
因为这种哈希算法很固定,同一个传入的字符串得到的hash字符串是相同的。以现在的手段来说,可以采用:
- 暴力枚举直接枚举原文并计算哈希值,然后再去比对一致的信息摘要
- 字典爆破,用一个巨大的字典来存储原始信息和对应哈希值的键值对,通过碰撞来比对映射关系
- 彩虹表,也是现在最多使用的办法(像之前的*习通信息泄露事件中)
虽然说这些破解方法的成本比较高,但在如今计算机算力势不可挡的发展下,利用分布式计算还是能很有效的进行破解。
加盐MD5
那可能会有人说了,加盐了解一下?确实加盐主要就是为了增加嗨客的计算成本,因为有了盐值要重新计算彩虹表所以在抵御彩虹表上确实有作用。但真的就安全了吗?这种情况下虽然每个加密hash字符串使用了随机的盐进行hash,但破解的方向转变成了哈希碰撞的概率。比如就算我不知道你的密码,不知道你的盐值。只要我能找到一个值经过加盐的hash后与你加盐后的密码一致照样能登录你的账号。
也就是说这还是个算力问题。除了知名的hashcat,下面是在一个靶场环境下使用 John (john the ripper)来爆破MD5

总的来说,用MD5、MD5加盐来存密码都是不够安全的。那更换其他的加密算法呢?这需要考虑一个大问题,那就是怎么去存储加密用的密钥呢?当数据泄露时又怎么保证密钥就能独善其身呢?
Bcrypt
更加安全的解决方案是现在广泛使用的bcrypt,他是基于 eksblowfish 算法设计的加密哈希函数。他的主要特点如下:
- 产生随机盐:这样对于同样的原始数据得到的hash都不同。他先生成随机的盐,再拿盐和原始数据进行hash
- 自适应性:他可以动态调整工作因子,前面提到了算力问题,而因为他这个特性任你算力多强他会自己增加迭代次数将加密速度控制在一个范围里面,直接硬抗暴力搜索。
那盐是随机的,每次做出的菜味道都不一样,又该怎么比对内容的一致性呢?他的校验是先从hash中取出salt,再去与内容进行hash,然后去比对之前加密的hash。比如下面加密的字符串:
$2a$10$te3Yi7z4fiH2xRw6vReet.XHRbd1iz711ykk6bFAL4y/nk213QOXS
$2a$为hash算法的唯一标识,这里表示Bcrypt。10是工作因子,代表2的10次方。te3Yi7z4fiH2xRw6vReet.这部分22长的字符是16字节的salt经base64编码后得到的,最后的部分是计算后的 Base64 哈希值(24 字节)
看一个例子:
package main
import (
"golang.org/x/crypto/bcrypt"
"fmt"
)
func encryptByBcrypt(str string) string {
bytes := []byte(str)
hashedBytes, err := bcrypt.GenerateFromPassword(bytes, bcrypt.DefaultCost)
if err != nil {
fmt.Println(err)
return ""
}
return string(hashedBytes)
}
func compare(format, input string) bool {
err := bcrypt.CompareHashAndPassword([]byte(format), []byte(input))
if err != nil {
return false
}
return true
}
func main() {
var (
// 用户输入
input1 = "admin666"
input2 = "admin"
// 数据库中存储的
dbData = encryptByBcrypt("admin666")
)
fmt.Printf("用户输入%s的加密结果: %s\n", input1, encryptByBcrypt(input1))
fmt.Printf("用户输入%s的加密结果: %s\n", input2, encryptByBcrypt(input2))
fmt.Printf("数据库中的加密字符串: %s\n", dbData)
for i := 2; i < 5; i++ {
fmt.Printf("第%d次登录时对%s加密的结果: %s ", i, input1, ecryptByBcrypt(input1))
fmt.Printf("%s是否匹配数据库中的值:%v\n", input1, compare(dbData, input1))
}
fmt.Printf("%s 是否匹配数据库中的值:%v", input2, compare(dbData, input2))
}
//结果:
//admin666的加密结果: $2a$10$Q1VWBHXkPxTT0oLQtvaKSOfXmz2CJIN2z7y1A9L.rcciJyxhtlMcu
//admin的加密结果: $2a$10$Z9JHgQQSEcQGIuVNhFmbpe3IdWLgR2ZjFhKQHU.2XXmWvrdXHpfZm
//数据库中的加密字符串: $2a$10$/IdAYwPf/mpnxH083nUxMuqigOuDQszgoVTjFnYMJJe3B0DFP3qNG
//第2次登录时对admin666加密的结果: $2a$10$TvHq/QzyK2mtW/VmDKEcPOp2KJ4qiKMcKzC709H0aUfqqv8dgC66u admin666是否匹配数据库中的值:true
//第3次登录时对admin666加密的结果: $2a$10$6X7DgbitO97hjDZfVfQa5.h1JNXWg0k65hc0PjhXHUnKhZhNFvoeK admin666是否匹配数据库中的值:true
//第4次登录时对admin666加密的结果: $2a$10$qtbVqqzU6V07RwMDg5.eG.SHzekcozQPeKqTewfXL9gVgt91OLXbe admin666是否匹配数据库中的值:true
//admin 是否匹配数据库中的值:false
可以看到当输入和数据库中存储加密的原始值相同时(admin666),虽然每次加密admin666的结果都不一样,但都能匹配通过,但输入不一样时(admin)一定不匹配。
再举一个看看他如何抵御暴力搜索:
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
"time"
)
func main() {
for cost := 10; cost <= 20; cost++ {
start := time.Now()
_, err := bcrypt.GenerateFromPassword([]byte("password"), cost)
if err != nil {
return
}
end := time.Since(start)
fmt.Printf("工作因子: %d, 耗时: %v\n", cost, end)
}
}
//结果
//工作因子: 10, 耗时: 58.073ms
//工作因子: 11, 耗时: 119.7431ms
//工作因子: 12, 耗时: 229.9239ms
//工作因子: 13, 耗时: 473.358ms
//工作因子: 14, 耗时: 934.7008ms
//工作因子: 15, 耗时: 1.8949588s
//工作因子: 16, 耗时: 3.7853585s
//工作因子: 17, 耗时: 7.808824s
//工作因子: 18, 耗时: 23.0166827s
//工作因子: 19, 耗时: 36.2171079s
//工作因子: 20, 耗时: 1m1.0674139s
可以看到每调整了cost(工作因子),加密的时间都会不断增加。当嗨客来硬碰硬的时候就直接提高cost增加他的成本。
MD5 or Bcrypt?的更多相关文章
- MD5,SHA1 都是哈希 摘要算法 MD5+SALT BCRYPT
为什么说 MD5 是不可逆的? md5是摘要算法,你学数据结构的时候学过哈希表吧?也有叫散列的.md5就是干那个用的 当然,如果硬要说的话...你可以用md5 hash一段字符串,也算是加密好了,不过 ...
- Java通过BCrypt加密
一.概述 在用户模块,对于用户密码的保护,通常都会进行加密.我们通常对密码进行加密,然后存放在数据库中,在用户进行登录的时候,将其输入的密码进行加密然后与数据库中存放的密文进行比较,以验证用户密码是否 ...
- Web项目开发中常见安全问题防范
本文章纯粹是个人收藏,其中各种也是略略了解,下面直接贴出知识点./捂脸/捂脸 计算机程序主要就是输入/输出,安全问题由此产生,凡是有输入的地方都可能带来安全风险.根据输入的数据类型,web应用主要有数 ...
- Ansible 小手册系列 十七(特性模块)
异步操作和轮询 --- # Requires ansible 1.8+ - name: 'YUM - fire and forget task' yum: name=docker-io state=i ...
- 信安周报-第03周:DB系统表
信安之路 第03周 前言 这周自主研究的任务如下: 任务附录的解释: 文件读写在通过数据库注入漏洞获取webshell的时候很有用 系统库和表存放了很多关键信息,在利用注入漏洞获取更多信息和权限的过程 ...
- php安全 过滤、验证、转义
不要相信外部源 $_GET $_POST $_REQUEST $_COOKIE $argv php://stdin php://input file_get_contents() 远程数据库 远程ap ...
- mongodb导入数据,保创建新项目
1.回顾 2.导入数据 2.1 excel数据表格 2.2 设计导入数据的路由 routes/users.js router.get('/upload', function (req, res, ne ...
- 如何生成安全的密码 Hash:MD5, SHA, PBKDF2, BCrypt 示例
密码 Hash 值的产生是将用户所提供的密码通过使用一定的算法计算后得到的加密字符序列.在 Java 中提供很多被证明能有效保证密码安全的 Hash 算法实现,我将在这篇文章中讨论其中的部分算法. 需 ...
- 用户角色权限查询添加bug集锦 用户密码加密 MD5 加盐 随机盐 spring的加密bcrypt
package cn.itcast.encode; import org.apache.commons.lang3.RandomStringUtils; import org.springframew ...
- 使用BCrypt算法加密存储登录密码用法及好处
//导入import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; /** *使用BCrypt算法加密存储登录密码 ...
随机推荐
- web应用及微信小程序版本更新检测方案实践
背景: 随着项目体量越来越大,用户群体越来越多,用户的声音也越来越明显:关于应用发版之后用户无感知,导致用户用的是仍然还是老版本功能,除非用户手动刷新,否则体验不到最新的功能:这样的体验非常不好,于是 ...
- Solution -「CF 392C」Yet Another Number Sequence
Description Link. 求 \(\sum_{i=1}^{n}\text{fibonacci}_{i}\times i^{k}=\sum_{i=1}^{n}(F_{i-1}+\text{fi ...
- k8s 自动扩缩容HPA原理及adapter配置详解👑
大家好,我是蓝胖子,都知道,k8s拥有自动扩缩容机制HPA,我们能够通过配置针对不同的扩缩容场景进行自动扩缩容,往往初学者在面对其中繁多配置的时候会学了又忘记,今天我将会以一种不同的视角,结合api ...
- 算法打卡|Day4 链表part02
Day4 链表part02 今日任务 ● 24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 ● 面试题 02.07. 链表相交 ● 142.环形链表II 目录 Day4 链表part0 ...
- Makefile 入门教程
Makefile 是一个非常强大的构建自动化工具,用于管理项目的编译.链接和其他构建任务.以下是一个详细的 Makefile 使用文档,包括基本概念.语法.示例和常见任务. 1. 基本概念 目标 (T ...
- Linux 中如何安全地抹去磁盘数据?
哈喽大家好,我是咸鱼 离过职的小伙伴都知道,离职的时候需要上交公司电脑,但是电脑里面有许多我们的个人信息(聊天记录.浏览记录等等) 所以我们就需要先把这些信息都删除,确保无法恢复之后才上交 即有些情况 ...
- 初探富文本之React实时预览
初探富文本之React实时预览 在前文中我们探讨了很多关于富文本引擎和协同的能力,在本文中我们更偏向具体的应用组件实现.在一些场景中比如组件库的文档编写时,我们希望能够有实时预览的能力,也就是用户可以 ...
- 题解 hdu 1269 迷宫城堡
找点图论练习题写,发现hdu又寄了,那就发到blog里吧. 思路:tarjan缩点判断DAG中点数是否为1.若是,则该图为强连通图. //produced by miya555 //stupid mi ...
- Istio 入门(六):版本控制
目录 VirtualService 和 DestinationRule VirtualService 与 Service 的关系 VirtualService 和 DestinationRule 的关 ...
- GameFramework摘录 - 1. ReferencePool
GameFramework是一个结构很优秀的Unity游戏框架,但意图似乎在构建可跨引擎的框架?对要求不高的小型个人(不专业)开发来说有些设计过度了,但其中的设计精华很值得学习. 首先来说一下其中的R ...