MD5 or Bcrypt?

摘要

首先是一个错误的认识观念问题,很多人觉得MD5是一个加密算法。不然,他实则是一种摘要算法,也可以叫哈希函数。他的作用是将目标文本转换成具有相同长度、不可逆的杂凑字符串。而加密算法和他恰恰相反,是将目标转换成具有不同长度、可逆的密文。

MD5简介

一般来说由于摘要算法他的单向运算,具有一定的不可逆性也就是说信息无法被还原了,所以成为加密算法中的一个构成部分。MD5他的具体原理可以看B站这个up的容易理解 传送门

但在现在看来任何场景下都最好不要使用MD5,因为他不够安全,跟存储明文没啥两样。可以使用诸如SHA256、SHA512这类其他的摘要算法来替代。MD5的不够安全从下面说起:

MD5的不安全性

因为这种哈希算法很固定,同一个传入的字符串得到的hash字符串是相同的。以现在的手段来说,可以采用:

  1. 暴力枚举直接枚举原文并计算哈希值,然后再去比对一致的信息摘要
  2. 字典爆破,用一个巨大的字典来存储原始信息和对应哈希值的键值对,通过碰撞来比对映射关系
  3. 彩虹表,也是现在最多使用的办法(像之前的*习通信息泄露事件中)

虽然说这些破解方法的成本比较高,但在如今计算机算力势不可挡的发展下,利用分布式计算还是能很有效的进行破解。

加盐MD5

那可能会有人说了,加盐了解一下?确实加盐主要就是为了增加嗨客的计算成本,因为有了盐值要重新计算彩虹表所以在抵御彩虹表上确实有作用。但真的就安全了吗?这种情况下虽然每个加密hash字符串使用了随机的盐进行hash,但破解的方向转变成了哈希碰撞的概率。比如就算我不知道你的密码,不知道你的盐值。只要我能找到一个值经过加盐的hash后与你加盐后的密码一致照样能登录你的账号。

也就是说这还是个算力问题。除了知名的hashcat,下面是在一个靶场环境下使用 John (john the ripper)来爆破MD5

总的来说,用MD5、MD5加盐来存密码都是不够安全的。那更换其他的加密算法呢?这需要考虑一个大问题,那就是怎么去存储加密用的密钥呢?当数据泄露时又怎么保证密钥就能独善其身呢?

Bcrypt

更加安全的解决方案是现在广泛使用的bcrypt,他是基于 eksblowfish 算法设计的加密哈希函数。他的主要特点如下:

  1. 产生随机盐:这样对于同样的原始数据得到的hash都不同。他先生成随机的盐,再拿盐和原始数据进行hash
  2. 自适应性:他可以动态调整工作因子,前面提到了算力问题,而因为他这个特性任你算力多强他会自己增加迭代次数将加密速度控制在一个范围里面,直接硬抗暴力搜索。

那盐是随机的,每次做出的菜味道都不一样,又该怎么比对内容的一致性呢?他的校验是先从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?的更多相关文章

  1. MD5,SHA1 都是哈希 摘要算法 MD5+SALT BCRYPT

    为什么说 MD5 是不可逆的? md5是摘要算法,你学数据结构的时候学过哈希表吧?也有叫散列的.md5就是干那个用的 当然,如果硬要说的话...你可以用md5 hash一段字符串,也算是加密好了,不过 ...

  2. Java通过BCrypt加密

    一.概述 在用户模块,对于用户密码的保护,通常都会进行加密.我们通常对密码进行加密,然后存放在数据库中,在用户进行登录的时候,将其输入的密码进行加密然后与数据库中存放的密文进行比较,以验证用户密码是否 ...

  3. Web项目开发中常见安全问题防范

    本文章纯粹是个人收藏,其中各种也是略略了解,下面直接贴出知识点./捂脸/捂脸 计算机程序主要就是输入/输出,安全问题由此产生,凡是有输入的地方都可能带来安全风险.根据输入的数据类型,web应用主要有数 ...

  4. Ansible 小手册系列 十七(特性模块)

    异步操作和轮询 --- # Requires ansible 1.8+ - name: 'YUM - fire and forget task' yum: name=docker-io state=i ...

  5. 信安周报-第03周:DB系统表

    信安之路 第03周 前言 这周自主研究的任务如下: 任务附录的解释: 文件读写在通过数据库注入漏洞获取webshell的时候很有用 系统库和表存放了很多关键信息,在利用注入漏洞获取更多信息和权限的过程 ...

  6. php安全 过滤、验证、转义

    不要相信外部源 $_GET $_POST $_REQUEST $_COOKIE $argv php://stdin php://input file_get_contents() 远程数据库 远程ap ...

  7. mongodb导入数据,保创建新项目

    1.回顾 2.导入数据 2.1 excel数据表格 2.2 设计导入数据的路由 routes/users.js router.get('/upload', function (req, res, ne ...

  8. 如何生成安全的密码 Hash:MD5, SHA, PBKDF2, BCrypt 示例

    密码 Hash 值的产生是将用户所提供的密码通过使用一定的算法计算后得到的加密字符序列.在 Java 中提供很多被证明能有效保证密码安全的 Hash 算法实现,我将在这篇文章中讨论其中的部分算法. 需 ...

  9. 用户角色权限查询添加bug集锦 用户密码加密 MD5 加盐 随机盐 spring的加密bcrypt

    package cn.itcast.encode; import org.apache.commons.lang3.RandomStringUtils; import org.springframew ...

  10. 使用BCrypt算法加密存储登录密码用法及好处

    //导入import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; /** *使用BCrypt算法加密存储登录密码 ...

随机推荐

  1. 支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<支持JDK19虚拟线程的web ...

  2. Vue项目——尚品会

    1: 项目的初始化 环境要求:node + webpack + 淘宝镜像 初始化项目: vue create 项目名称 目录/文件分析: - node_modules文件夹:放置项目依赖的地方 - p ...

  3. Python比较字符串格式类型时间大小

    已知的格式是 06/24/2021 15:47:01.491 时间比较的思路是,把数据转换成时间戳比较: 第一步是把 06/24/2021 15:47:01.491 格式转换称 2021-06-24 ...

  4. Django框架——模型层单表操作、模型层多表操作、模型层常用和非常用字段和参数、模型层进阶

    文章目录 1 模型层-单表操作 一 ORM简介 二 单表操作 2.1 创建表 1 创建模型 2 更多字段 3 更多参数 4 settings配置 5 增加,删除字段 2.2 添加表纪录 2.3 查询表 ...

  5. python第2~5章 学习笔记

    # 第2~5章 学习笔记 ## 什么是计算机语言 计算机就是一台用来计算机的机器,人让计算机干什么计算机就得干什么! 需要通过计算机的语言来控制计算机(编程语言)! 计算机语言其实和人类的语言没有本质 ...

  6. Stable Diffusion

     Stable Diffusion  ...using diffusers Stable Diffusion is a text-to-image latent diffusion model cre ...

  7. 关于 iPhone 上的相机功能

    关于 iPhone 上的相机功能 了解 iPhone 上的摄影风格.快录功能.超广角摄像头和其他相机功能.   通过摄影风格功能锁定您的风格 借助 iPhone 13 各款机型和 iPhone SE( ...

  8. Chromium Mojo通信

    Mojo 是一个跨平台 IPC 框架,它诞生于 chromium ,用来实现 chromium 进程内/进程间的通信.目前,它也被用于 ChromeOS. 在我们代码应用中,如何使用Mojo来作进程间 ...

  9. 9.24 多校联测 Day4 总结

    没有罚坐,但好像什么也没做. 反向挂分,RP++. 开考推 T1 的 k=2.推推推,写写写,假了.又假了.还是假的. 此时已过去 1h,开 T2,没有看懂题,又看了一会依旧没有看懂. 开 T3.尝试 ...

  10. HTML-8

    (一)引用数据类型 object function array object JavaScript对象用花括号来书写 对象属性是name:value由逗号分隔 var x={firstname:&qu ...