为了账号安全,请及时绑定邮箱和手机立即绑定

加密/散列数据库中的纯文本密码

/ 猿问

加密/散列数据库中的纯文本密码

慕运维8079593 2019-08-15 16:40:23

加密/散列数据库中的纯文本密码

继承了一个Web应用程序,我刚刚在SQL Server数据库中以纯文本形式存储了超过300,000个用户名/密码。我意识到这是一件非常糟糕的事情。

知道我必须更新登录和密码更新过程以加密/解密,并且对系统其余部分的影响最小,您会建议从数据库中删除纯文本密码的最佳方法是什么?

任何帮助表示赞赏。

编辑:对不起,如果我不清楚,我打算问你的加密/哈希密码的程序,而不是特定的加密/散列方法。

我应该只是:

  1. 备份数据库

  2. 更新登录/更新密码代码

  3. 几小时后,浏览用户表中记录密码的所有记录并替换每个记录

  4. 测试以确保用户仍然可以登录/更新密码

我想我的关注更多来自于大量的用户,所以我想确保我正确地做到这一点。


查看完整描述

3 回答

?
精慕HU

我想你必须在数据库中为加密密码添加一列,然后在获取当前密码的所有记录上运行批处理作业,对其进行加密(因为其他人提到像md5这样的哈希是非常标准的编辑:但不应该单独使用 - 请参阅其他答案以获得良好的讨论),将其存储在新列中并检查所有内容是否顺利进行。

然后,您需要更新前端以在登录时散列用户输入的密码,并验证是否与存储的散列相比,而不是检查明文与明文。

在最终将明文密码全部删除之前,将两个列保留一段时间以确保没有任何错误发生,这似乎是谨慎的做法。

不要忘记,只要密码被访问,代码就必须更改,例如密码更改/提醒请求。你当然会失去通过电子邮件发送忘记密码的能力,但这不是坏事。您将不得不使用密码重置系统。

编辑:最后一点,您可能要考虑避免我第一次尝试在测试床安全登录网站上犯的错误:

处理用户密码时,请考虑进行散列的位置。在我的例子中,哈希是由在Web服务器上运行的PHP代码计算的,但密码是以明文形式从用户机器传输到页面的!这在我工作的环境中是可以的(ish),因为它无论如何都在https系统内(uni网络)。但是,在现实世界中,我想你会想要在离开用户系统之前对密码进行哈希处理,使用javascript等,然后将哈希传输到你的站点。


查看完整回答
反对 回复 2019-08-15
?
慕沐林林

按优先顺序使用Argon2scryptbcryptPBKDF2。尽可能使用适合您情况的减速因子。使用经审查的现有实施。确保使用适当的盐(尽管您正在使用的库应该为您确保这一点)。


当您对密码进行散列时,请使用DO NOT USE PLAIN MD5

使用PBKDF2,这基本上意味着使用随机盐来防止彩虹表攻击,并且迭代(重新散列)足够的时间来减慢散列 - 不要太多,以至于你的应用程序需要太长时间,但足以让攻击者暴力破解大量不同的密码会注意到

从文件:

  • 迭代至少1000次,最好是更多 - 实现时间,看看有多少次迭代对你来说是可行的。

  • 8个字节(64位)的盐就足够了,并且随机数不需要是安全的(盐是未加密的,我们不担心有人猜它)。

  • 在散列时应用salt的一种好方法是使用HMAC和您喜欢的哈希算法,使用密码作为HMAC密钥,使用salt作为哈希文本(请参阅文档的这一部分)。

Python中的示例实现,使用SHA-256作为安全哈希:

编辑:正如Eli Collins所提到的,这不是PBKDF2的实现。您应该更喜欢坚持标准的实现,例如PassLib

from hashlib import sha256from hmac import HMACimport randomdef random_bytes(num_bytes):
  return "".join(chr(random.randrange(256)) for i in xrange(num_bytes))def pbkdf_sha256(password, salt, iterations):
  result = password
  for i in xrange(iterations):
    result = HMAC(result, salt, sha256).digest() # use HMAC to apply the salt
  return resultNUM_ITERATIONS = 5000def hash_password(plain_password):
  salt = random_bytes(8) # 64 bits
  hashed_password = pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)
  # return the salt and hashed password, encoded in base64 and split with ","
  return salt.encode("base64").strip() + "," + hashed_password.encode("base64").strip()def check_password(saved_password_entry, plain_password):
  salt, hashed_password = saved_password_entry.split(",")
  salt = salt.decode("base64")
  hashed_password = hashed_password.decode("base64")
  return hashed_password == pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)password_entry = hash_password("mysecret")print password_entry # will print, for example: 8Y1ZO8Y1pi4=,r7Acg5iRiZ/x4QwFLhPMjASESxesoIcdJRSDkqWYfaA=check_password(password_entry, "mysecret") # returns True


查看完整回答
反对 回复 2019-08-15
?
动漫人物

基本策略是使用密钥派生函数用一些盐“哈希”密码。salt和哈希结果存储在数据库中。当用户输入密码时,盐和它们的输入以相同的方式进行散列并与存储的值进行比较。如果匹配,则对用户进行身份验证。

细节决定成败。首先,很大程度上取决于所选择的哈希算法。像PBKDF2这样的密钥派生算法,基于基于散列的消息认证代码,使得在计算上不可行地找到将产生给定输出的输入(在这种情况下,密码)(攻击者在数据库中找到了什么) )。

预先计算的字典攻击使用预先计算的索引或字典,从散列输出到密码。散列很慢(或者它应该是,无论如何),因此攻击者一次性散列所有可能的密码,并以这样的方式存储索引结果,即给定散列,他可以查找相应的密码。这是时间空间的经典权衡。由于密码列表可能很大,因此有一些方法可以调整权衡(如彩虹表),这样攻击者就可以放弃一点速度来节省大量空间。

使用“加密盐”阻碍了预计算攻击。这是一些使用密码进行哈希处理的数据。它不需要是秘密,它只需要对给定的密码不可预测。对于盐的每个值,攻击者需要一个新的字典。如果使用一个字节的salt,攻击者需要256个字典副本,每个副本使用不同的盐生成。首先,他使用salt查找正确的字典,然后他使用hash输出来查找可用的密码。但是如果添加4个字节怎么办?现在他需要40亿份字典。通过使用足够大的盐,排除了字典攻击。实际上,来自加密质量随机数发生器的8到16个字节的数据是很好的。

通过预先计算表,攻击者可以在每次尝试时计算哈希值。现在找到密码需要多长时间完全取决于散列候选人所需的时间。通过散列函数的迭代来增加该时间。数字迭代通常是密钥导出函数的参数; 今天,许多移动设备使用10,000到20,000次迭代,而服务器可能使用100,000或更多。(bcrypt算法使用术语“成本因子”,它是所需时间的对数度量。)


查看完整回答
反对 回复 2019-08-15
  • 3 回答
  • 0 关注
  • 289 浏览
我要回答
慕课专栏
更多

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信