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算法加密存储登录密码 ...
随机推荐
- 「luogu - P3158」「cqoi 2011」放棋子
link. 解读一下,大概就是一种颜色放进去就会占据一行一列,dp 状态就好想了:\(f_{i,j,k}\) 表示恰好用完前 \(k\) 种颜色的所有棋子,占据了 \(i\) 行 \(j\) 列的方案 ...
- Solution -「SCOI 2016」萌萌哒
Description Link. 给定一个长度为 \(n\) 的数组让你填数,需要满足 \(m\) 个形如 \(([l_{1},r_{1}],[l_{2},r_{2}])\) 的要求,这两个区间填好 ...
- maven缺失ojdbc6解决方法(手动安装ojdbc6)
maven缺失ojdbc6解决方法(手动安装ojdbc6) 1. 首先下载ojdbc6jar包 jar下载地址一(需登录) jar下载地址二(直接下载) 2. 进入到jar包所在文件夹,执行cmd命令 ...
- vue2实现数据聚合【scatter-clustering】组件封装
实现如下效果: 效果展示:https://code.juejin.cn/pen/7228568245148581943 如果不会请移步到官网的栗子,请点击查看 直接给大家上代码: 整体代码片段 1 & ...
- Springboot实现注解判断权限
Springboot实现注解判断权限 今天记录一下使用springboot的注解来给方法加权限 避免了每个方法都需要大量的权限判断 超级好用√ @ 目录 Springboot实现注解判断权限 1.创建 ...
- 解决在VS Code中运行有中文字符的Java代码(第三种方式),出现编码 GBK 的不可映射字符 (0x81)
写代码时,我们不避免的会使用一些中文注释,这些在其他的语言中没有问题.但是在Java的注释里面如果有中文字符,就会报错.即使文件编码是utf-8也无济于事.是因为使用CMD运行java程序的时候,系统 ...
- PKCS#11:密码设备与应用程序的密码学接口
密码学在信息安全中扮演着至关重要的角色.为了保护敏感信息.数字身份和网络通信的安全性,密码设备(如硬件安全模块HSM)与应用程序之间的安全通信和互操作性变得至关重要.PKCS#11(Public-Ke ...
- mysql修改密码和开启远程访问
mysql默认是关闭远程访问的,开启命令如下 1.首先打开mysql所在的bin目录,C:\Program Files\MySQL\MySQL Server 5.5\bin 在地址栏输入cmd,回车 ...
- AT通讯总结(56K猫调制解调器Modem)型号I-56EM
1.关闭流控RTS与DTR AT&D0&K0\r\n 2.保存到非易失性存储 AT&W\r\n 3.向800001音频拨号 ATDT800001\r\n 4.接听 ATA\r\ ...
- 洛谷1451(BFS)
#include"bits/stdc++.h" using namespace std; int mp[110][110]; bool vis[110][110]; int dx[ ...