面试官:你们是如何在数据库中存储密码?

我有一个朋友,姑且就先称呼他为小王吧,前几日,小王去面试;

面试官问:如何在数据库中存储密码?

场景: 小王是应聘者,张总是面试官,面试主要围绕密码存储和相关的安全技术展开。


张总:“你好,小王。我看到你在简历中提到对密码安全有一些了解。你能简单说说,当我们要存储用户密码时,应该采取哪些措施吗?”

小王:“当然,密码是敏感信息,所以我们需要对它进行加密,以确保它在数据库中被保护好。”

张总:“加密?你是指密码存储时需要加密吗?能解释一下吗?”

小王:“是的,我们可以使用加密算法,比如AES,把密码加密后存储在数据库中。”

张总:“你确定是要加密吗?如果我们加密了密码,系统在验证用户登录时,需要解密密码来做对比。这样安全吗?”

小王:“嗯……我想也许不应该解密密码。可能是哈希处理更合适?”

张总:“对的。我们通常不会加密密码,而是进行哈希处理,因为哈希是不可逆的。你知道为什么这样做吗?”

小王:“我想是为了防止密码泄露。即使数据库被入侵,黑客也无法直接获取明文密码。”

张总:“没错。不过单单哈希处理是不够的。你知道彩虹表攻击吗?”

小王:“彩虹表?听过一些,好像是与破解哈希值相关的?”

张总:“对,彩虹表是预计算的哈希值表,攻击者可以用它来匹配数据库中的哈希值,找到对应的明文密码。所以,仅仅依赖哈希值是不够的。你知道我们还能做些什么来防止这种攻击吗?”

小王:“加盐?我们可以为每个密码生成一个随机的盐值,然后一起哈希处理。”

张总:“没错,加盐是防止彩虹表攻击的重要措施。通过添加独特的随机盐,我们可以大大增加破解的难度。你能举例说明你会用什么哈希算法吗?”

小王:“我们公司之前使用了SHA-256来哈希密码。我听说它比MD5更安全。”

张总:“SHA-256确实比MD5安全很多,但实际上对于密码哈希,还有更合适的选择。你听说过Argon2吗?”

小王:“Argon2是专为密码哈希设计的算法,获得了2015年的密码学竞赛大奖。它可以设置内存使用和迭代次数,这让它在应对暴力破解时更加有效。相比于SHA-256,Argon2能够抵御针对现代硬件的并行攻击。”

张总:“听起来很强大。那我们为什么不直接用SHA-256呢?它不是很常用吗?”

小王:“SHA-256是一种通用的哈希算法,主要用于数据完整性验证,比如区块链和数字签名。但是,它在密码学上的应用不如像Argon2这样的专门密码哈希算法。密码哈希需要应对暴力破解和时间复杂度的问题,而Argon2能够提供更好的防护。”

张总内心:“小伙子还不错…是个人才。”


今天我们就结合我这位小王朋友的面试经验来深入的聊一聊:如何在数据库中存储密码?


为什么我们只能重置密码而不是找回原密码?

你是否也曾有过这样的困惑:为什么当我们忘记一个账号的登录密码并点击“忘记密码”时,系统总是让我们创建一个新密码,而不是告诉我们原来的密码呢?

你可能觉得这有些不便,因为有时你只想知道原来的密码,而不想再想一个新密码。然而,当你深入学习编程后,你会发现这里面有非常合理的安全考量。

在这篇文章中,我们将仔细讨论这个问题,帮助那些曾经或现在对这一问题有同样困惑的同学们理解背后的原因。

直接存储明文密码的风险

让我们假设一个用户在你的网站上注册了一个账号,例如 xw@qq.com,并设置了密码为 abc654321。最直接的方式是将用户的密码以明文形式存储在数据库中:

username      password
xw@qq.com     abc654321

这种方法虽然简单易懂,但存在巨大的安全隐患。如果黑客获取了你的数据库访问权限,他不仅能看到这个用户的密码,还能轻易猜到用户在其他网站上使用的相同账号和密码。事实上,很多用户在多个网站上会使用相同的邮箱和密码组合,这使得黑客可以通过攻破一个网站,获得多个网站的用户信息。因此,存储明文密码几乎没有任何保障。

哈希算法:密码不可逆存储

为了解决明文存储带来的风险,开发人员通常会将密码转换为不可逆的哈希值,然后将哈希值存储在数据库中。例如:

username         password
xw@qq.com        5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

在这个例子中,密码 abc654321 被通过哈希算法(如 SHA-1 或 SHA-256)转换成了一串不可逆的字符。即使黑客获取了这个哈希值,他们也不能直接通过哈希值反推原始密码。

为什么这样做?

保护用户隐私:如果系统能够恢复或查看原始密码,这样一来,系统本身就会有用户密码的明文副本。这将极大地增加密码泄露的风险。

防止数据泄露后滥用:即使黑客侵入数据库,获得了密码的哈希值,也无法通过这些哈希值反向计算出原始密码。这种设计大大降低了密码被盗后的风险。

然而,哈希算法并不是完全防御性的。虽然哈希是单向的,但黑客可以通过暴力破解或使用预先计算的哈希值表(例如彩虹表)进行反推。这就是为什么哈希算法的计算速度越快,越不适合密码存储。例如,SHA-1 计算速度非常快,因此不适合直接用于密码哈希。

使用 SHA-256 进行密码哈希

import hashlibdef hash_password_sha256(password: str) -> str:# 使用 SHA-256 哈希算法sha_signature = hashlib.sha256(password.encode()).hexdigest()return sha_signature# 示例
password = "abc654321"
hashed_password = hash_password_sha256(password)
print("SHA-256 哈希值:", hashed_password)

这个方法虽然比存储明文密码要安全,但仍然不足以抵御现代的暴力破解攻击。

加盐哈希:防止彩虹表攻击

什么是彩虹攻击?

彩虹表攻击是一种通过预先计算大量常见密码及其哈希值的方式,试图快速破解哈希密码的技术。攻击者可以利用这些表进行快速查找,匹配数据库中的哈希值,从而获得密码。
在这里插入图片描述

彩虹表攻击模拟

import hashlib# 简单模拟常见密码字典
common_passwords = ["123456", "password", "abc123", "qwerty", "letmein"]# 用来存储常见密码的哈希值(即模拟彩虹表)
rainbow_table = {}# 创建彩虹表 (使用 SHA-256 哈希算法)
def create_rainbow_table():for password in common_passwords:hashed_password = hashlib.sha256(password.encode()).hexdigest()rainbow_table[hashed_password] = passwordprint("彩虹表生成成功!")# 模拟攻击者通过彩虹表破解密码哈希
def crack_password(hashed_password):# 尝试使用彩虹表查找原始密码if hashed_password in rainbow_table:return rainbow_table[hashed_password]else:return None# 创建彩虹表
create_rainbow_table()# 模拟数据库中存储的哈希密码
stored_hashed_password = hashlib.sha256("abc123".encode()).hexdigest()
print("存储的哈希密码:", stored_hashed_password)# 尝试通过彩虹表破解存储的哈希密码
cracked_password = crack_password(stored_hashed_password)
if cracked_password:print(f"密码已破解: {cracked_password}")
else:print("未能破解密码")

彩虹表生成:我们首先创建了一个简单的彩虹表,包含常见密码的哈希值。实际的彩虹表会非常庞大,包含数百万甚至更多的常见密码及其哈希值。

攻击模拟:我们尝试通过彩虹表匹配数据库中存储的哈希密码。如果找到了对应的哈希值,我们就可以还原出原始密码。

彩虹表攻击的限制:

彩虹表虽然有效,但也有局限性,特别是当密码存储中使用了加盐技术时:

加盐防御:每个密码都有独立的随机盐,即使彩虹表中包含了相同的密码,也无法匹配到哈希值。这样,即便攻击者获取了数据库,他们也需要逐个破解每个密码。

bcrypt 和其他“慢”哈希算法:像 bcrypt、PBKDF2 这样的密码哈希算法不仅会自动使用盐,还会通过增加计算时间来进一步增加破解难度。

什么是加盐?

这里的加盐,可不是我们吃的食用盐,加盐,其实是编程中的一个概念,用来让密码更安全。要理解它,你可以想象一下我们日常生活中的一个情景。
在这里插入图片描述
假设你喜欢喝咖啡,大家也都喜欢喝咖啡。有的人喜欢加糖,有的人喜欢不加糖。现在,如果我给你一杯完全相同的黑咖啡,不加糖,你一口就能尝出来这就是纯咖啡,跟别人杯子里的咖啡味道一模一样。黑客破解密码也是这样,如果所有人的密码存储方式都是直接拿密码去做哈希,黑客就可以通过匹配很多“常见的黑咖啡”(简单密码)来破解你的密码。

加盐,就像往咖啡里加上一点“独特的调料”,比如糖、奶油,甚至其他你喜欢的配料。这样,即使两个人的咖啡原料是一样的(比如密码相同),但每个人往里面加了不同的配料,结果喝起来味道就完全不同了。

在密码存储中,“盐”就是这份独特的调料。每次你设置密码,系统会给你的密码加一点“盐”(一串随机生成的字符串)。当系统保存你的密码时,它保存的是密码加上盐后的一串哈希值(类似你加了调料后咖啡的味道)。这样,即使黑客知道别人的密码是“123456”,但因为你加了不同的盐,他破解的时候还是搞不清你到底用了什么密码

举个更简单的例子:

假设你和朋友都设置了相同的密码“password”。如果不加盐,黑客拿到了一个人的密码哈希值,马上就能推断出你和其他人的密码都是“password”。

但如果加了盐,相当于每个人的密码不再是简单的“password”,而是变成了“salt1+password”(你加了一点盐1)和“salt2+password”(你的朋友加了点不同的盐2)。这样,即使密码一样,黑客看到的东西却完全不同——他们就没法通过一个哈希值破解出所有人的密码了。

所以,“加盐”就是密码里的独特调味料,让黑客破解起来更费劲,让你的密码更安全。

username         salt                      password
xw@qq.com        2dc7fcc...                sha256("2dc7fcc..." + password_1)
john@163.com     afadb2f...                sha256("afadb2f..." + password_2)

所以,“加盐”就是密码里的独特调味料,每个用户的密码都会有一个唯一的盐值,即使黑客得到了数据库,也无法通过彩虹表轻易破解密码,让你的密码更安全。

请在此添加图片描述

使用随机盐的 SHA-256 哈希

import os
import hashlibdef generate_salt() -> str:# 生成16字节的随机盐值return os.urandom(16).hex()def hash_password_with_salt(password: str, salt: str) -> str:# 使用 SHA-256 和随机盐哈希密码salted_password = salt + passwordsha_signature = hashlib.sha256(salted_password.encode()).hexdigest()return sha_signature# 示例
password = "abc654321"
salt = generate_salt()
hashed_password = hash_password_with_salt(password, salt)
print("随机盐:", salt)
print("哈希后的密码:", hashed_password)

更安全的密码哈希算法:bcrypt 和 PBKDF2

虽然 SHA-256 加盐哈希增强了密码的安全性,但依然存在一定的破解风险。bcryptPBKDF2 这样的算法专为密码存储设计,它们的计算速度比常规哈希算法要慢得多,从而增加破解难度。这些算法内置了随机盐,并且可以根据需要调整计算成本。

使用 bcrypt 进行密码哈希

import bcryptdef hash_password_bcrypt(password: str) -> str:# 生成盐并哈希密码salt = bcrypt.gensalt()  # 自动生成盐hashed_password = bcrypt.hashpw(password.encode(), salt)return hashed_passworddef check_password_bcrypt(password: str, hashed_password: str) -> bool:# 验证密码return bcrypt.checkpw(password.encode(), hashed_password)# 示例
password = "abc654321"
hashed_password = hash_password_bcrypt(password)
print("bcrypt 哈希后的密码:", hashed_password)# 验证密码
is_valid = check_password_bcrypt(password, hashed_password)
print("密码验证结果:", is_valid)

密码重置:安全性考量

正因为密码是以不可逆的方式存储的,当用户忘记密码时,系统无法直接告诉用户原来的密码。相反,系统会通过重置密码的方式来确保安全性。通过发送验证码或其他身份验证方式,确保只有合法用户能够重置密码。这种方式能有效防止恶意用户通过系统获取密码。

总结

存储密码的正确方式至关重要。无论是使用哈希算法、加盐技术,还是采用更安全的密码哈希算法(如 bcrypt 和 PBKDF2),最终目的都是为了保护用户数据免受攻击。而允许用户重置密码而不是查看原始密码,则是确保密码安全存储的必要手段。通过本文,希望你对密码存储背后的原理和安全性考量有了更深的理解。


额外补充:

  1. HMAC(哈希消息认证码):可以进一步加强密码的安全性,尤其是在服务器和数据库分离时。
  2. 密码管理工具:使用密码管理工具生成和保存复杂的密码,也是对用户教育的一部分,减少了用户重复使用简单密码的风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143325.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基于PHP+MySQL组合开发的在线客服源码系统 聊天记录实时保存 带完整的安装代码包以及搭建部署教程

系统概述 随着互联网技术的飞速发展,企业与客户之间的沟通方式日益多样化,在线客服系统作为连接企业与客户的桥梁,其重要性不言而喻。然而,市场上现有的在线客服系统往往存在成本高、定制性差、维护复杂等问题。针对这些痛点&…

idea插件开发的第四天-完善JSON工具

介绍 Demo说明 本文基于maven项目开发,idea版本为2022.3以上,jdk为1.8本文在Tools插件之上进行开发本次demo将使用idea的一些组件优化 Tools插件说明 Tools插件是一个Idea插件,此插件提供统一Spi规范,极大的降低了idea插件的开发难度,并提供开发者模块,可以极大的为开发者开…

C++源代码封装成dll动态链接库,并在WPF项目中使用的步骤说明

文章目录 1. 创建并生成C的DLL(C动态链接库)(1)新建项目-->开发语言选定C,在搜索栏搜索“动态链接库”-->配置项目名称和路径-->添加类,此处命名为My_C_Class(2)实现类的功能&#xff…

Logstash 安装与部署(无坑版)

下载 版本对照关系:ElasticSearch 7.9.2 和 Logstash 7.9.2 ; 官方下载地址 选择ElasticSearch版本一致的Logstash版本 https://www.elastic.co/cn/downloads/logstash 下载链接:https://artifacts.elastic.co/downloads/logstash/logst…

Flask-WTF的使用

组织一个 Flask 项目通常需要遵循一定的结构,以便代码清晰、可维护。下面是一个典型的 Flask 项目结构: my_flask_app/ │ ├── app/ │ ├── __init__.py │ ├── models.py │ ├── views.py │ ├── forms.py │ ├── templat…

什么样的无线麦克风好?罗德、西圣、优篮子无线麦克风实测对比

在这个人人都在用短视频分享记录生活的时代,拍摄生活Vlog和短视频已经深入我们生活的方方面面,美食分享、搞笑视频以及直播等等,不过既然说到视频创作,那么光有好的内容画面肯定是远远不够的,试想一段视频里杂音不断&a…

单片机带隙电压基准电路

单片机带隙电压基准电路 一、带隙电压基准电路概述 带隙电压基准电路在单片机中占据着至关重要的地位。它能够为各种模拟集成电路提供稳定的参考电压,确保电路的正常运行。例如,在高精度的比较器中,带隙电压基准电路可以提供一个精确的参考…

【可测试性实践】C++单元测试:gtest gmock

引言 google test是目前C主流的单元测试框架,本文介绍如何在工程引入gtest和gmock,并提供入门参考示例。根据黄金圈思维我们先思考Why(为什么做),为什么我们要进行单元测试,为什么要引入mock手段来测试代码…

IBM中国研发部裁员:全球化背景下的中国IT产业挑战与机遇

文章目录 每日一句正能量前言整体分析人才发展裁员对中国IT人才市场的影响:IT从业者提升竞争力的策略: 产业未来后记 每日一句正能量 一切美好的事物都是曲折地接近自己的目标,一切笔直都是骗人的,所有真理都是弯曲的,…

设计一个高质量的API接口:提升应用性能的关键步骤

在当今的软件开发世界中,API(应用程序编程接口)接口扮演着至关重要的角色。一个设计精良的API不仅能够提高开发效率,还能提升用户体验,并确保系统的可扩展性和安全性。本文将探讨如何设计一个高质量的API接口&#xff…

蓝卓标杆客户镇洋发展,荣获IDC中国未来企业大奖

9月11-12日,2024 IDC中国年度盛典暨颁奖典礼在上海正式举办,年度盛典公布了2024 IDC中国未来企业大奖等系列奖项,以此表彰不同机构/组织/个人在数字化转型大背景下的努力与成绩。 其中,浙江镇洋发展股份有限公司(以下简…

【sgCreateCallAPIFunction】自定义小工具:敏捷开发→调用接口方法代码生成工具

<template><div :class"$options.name" class"sgDevTool"><sgHead /><div class"sg-container"><div class"sg-start"><div style"margin-bottom: 10px">调用接口方法定义列表</div…

Gradio导入AIGC大模型创建web端智能体聊天机器人,python(2)

Gradio导入AIGC大模型创建web端智能体聊天机器人&#xff0c;python&#xff08;2&#xff09; 选用这个大模型&#xff1a; https://huggingface.co/HuggingFaceTB/SmolLM-1.7B-Instructhttps://huggingface.co/HuggingFaceTB/SmolLM-1.7B-Instruct原因是该模型相对比较小&am…

使用Dev-C++实现比大小的C语言程序

使用Dev-C++实现比大小的C语言程序 引言一、Dev-C++开发环境简介与安装1.1 Dev-C++简介1.2 Dev-C++安装步骤二、初识C语言与Dev-C++的使用2.1 C语言基础2.2 创建一个新的C项目2.3 编写简单的C程序2.4 编译与运行三、编写比大小的C程序3.1 程序需求3.2 程序设计3.3 编写代码3.4 …

dubbo三

dubbo dubbo架构各层说明 URL举例解析 消费者引用服务过程 项目初始化

.ideavimrc在idea打不开

### bug修复 自己不知道搞了啥导致.ideavimrc文件打不开&#xff0c;如图点击无反应 ![[Pasted image 20240917004710.png|400]] 后面发现是格式类型的错误 参考[这篇文章](https://blog.csdn.net/qq_41147260/article/details/85002668) **修复** - AltCtrls 打开设置 - Edi…

win11:重命名文件自动改变位置

你用的系统有个小bug 就是在桌面上重命名文件之后 文件会自动跳转到左上角 有些不注意的以为文件丢了 分类摆放好的文件 重命名之后还得拉回原来的位置 其实简单设置一下 就可以修复这个小bug 1、我们找到设置 在搜索栏搜索“个性化”&#xff0c;选择---‘开始’菜单设置 2、…

【北京迅为】《STM32MP157开发板使用手册》- 第三十一章Cortex-M4窗口看门狗实验

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

java进销存系统源码:管店云进销存解决方案

在当今数字化转型的大背景下&#xff0c;企业对高效、可靠的进销存管理系统的需求日益增长。Java作为一种广泛使用的编程语言&#xff0c;以其成熟的技术栈和强大的生态系统&#xff0c;成为了开发高性能进销存系统的首选语言之一。本文将介绍一款基于Java进销存系统源码的“管…

yolov5s网络结构

鉴于网上关于yolov5s的解读众多然不尽相同&#xff0c;特从YOLOv5官方项目地址&#xff1a;https://github.com/ultralytics/yolov5下载了yolov5的各版本文件并上传至 [资源] 栏目&#xff0c;这里就yolov5s版本的网络结构进行分析展示。 1、yolov5s模型的yaml文件 # Ultralyt…