我应该在将密码发送到服务器端之前对其进行哈希处理吗?

Jad*_*ias 100 security authentication https login

我注意到大多数站点通过HTTPS将密码作为纯文本发送到服务器.有没有什么优势,而不是我发送密码的哈希到服务器?会更安全吗?

小智 147

这是一个老问题,但我觉得有必要就这个重要问题提出我的意见.这里有很多错误的信息

OP从未提及通过HTTP清除发送密码 - 只有HTTPS,但许多人似乎都在回应因某种原因通过HTTP发送密码的问题.那说:

我认为绝不应该以纯文本保留密码(更不用说传输)了.这意味着不能保存在磁盘上,甚至不能保存在内存中.

在这里回复的人似乎认为HTTPS是一个银弹,但事实并非如此.但它肯定会有很大帮助,并且应该在任何经过​​身份验证的会话中使用.

实际上没有必要知道原始密码是什么. 所需要的只是基于用户选择的原始文本生成(并可靠地重新生成)认证"密钥"的可靠方式.在理想的世界中,这个文本应该通过使用不可逆盐来散列它来立即生成"密钥".此salt对于生成的用户凭据应该是唯一的.这个"密钥"将是您的系统用作密码的密钥.这样,如果您的系统将来会受到攻击,这些凭据将只对您自己的组织有用,而且在其他任何地方,用户都懒惰并使用相同的密码.

所以我们有一把钥匙.现在我们需要清理客户端设备上的任何密码跟踪.

接下来,我们需要为您的系统获取该密钥.您绝不应该"明确地"传输密钥或密码.甚至不是通过HTTPS.HTTPS不是不可穿透的.实际上,许多组织可以成为受信任的MITM - 不是从攻击的角度来看,而是对流量进行检查以实现自己的安全策略.这削弱了HTTPS,并不是它发生的唯一方式(例如重定向到HTTP MITM攻击).永远不要认为它是安全的.

为了解决这个问题,我们使用一次性随机数来散列密钥.此随机数对于每次提交系统密钥都是唯一的 - 即使在同一会话期间,如果您需要多次发送,也会使用相同的凭据.一旦它到达您自己的系统,您就可以撤消该nonce以恢复身份验证密钥,并对请求进行身份验证.

此时,我会在它永久存储在您自己的系统中之前,不可逆转地将其最后一次哈希.这样,您可以为了SSO等目的与合作伙伴组织共享凭据,同时能够证明您自己的组织不能冒充用户.这种方法的最佳部分是,您永远不会在未经授权的情况下共享用户生成的任何内容.

做更多的研究,因为它有更多的内容,甚至我已经泄露,但如果你想为你的用户提供真正的安全性,我认为这种方法目前是最完整的响应.

TL; DR:

使用HTTPS.使用每个密码的唯一salt安全地哈希密码,不可逆转.在客户端上执行此操作 - 不要传输其实际密码.将用户原始密码传输到服务器永远不会"正常"或"正常".清除原始密码的任何痕迹.无论HTTP/HTTPS如何,都使用随机数.它在许多层面上都更加安全.(对OP的回答).

  • +1不假设HTTPS是银弹. (46认同)
  • 我刚检查了gmail和facebook - chrome开发人员工具告诉我两个POST都带有包含我的用户名和密码的urlencoded消息(普通(未加盐))文本.大客户如何/为什么不在客户端使用nonce salting? (23认同)
  • 您使用nonce散列密钥并声称能够在服务器端反转nonce.你是否强制执行哈希呢?或者当你获得hash = HASH(secret + nonce)时如何检索一个nonce HASH应该是一个不可逆转的函数.你实现了这个吗?我不认为你解释的是可行的.你能创建协议的流程图吗? (15认同)
  • 如果你不信任HTTPS,那么每一次努力都是毫无意义的!您的代码本身通过网络发送,攻击者可以修改/替换您在传输过程中保护密码的所有尝试 (15认同)
  • 这个答案有很多错误信息,在大多数情况下使用 HTTPS 并在存储到服务器数据库之前对密码进行哈希处理就足够了。对于更重要的帐户,请使用多重身份验证而不是客户端哈希。有关更多信息,请参阅:[我只是通过 https 发送用户名和密码。这样可以吗?](https://security.stackexchange.com/q/7057),[https 安全 - 密码应该在服务器端还是客户端进行哈希处理?答](https://security.stackexchange.com/q/8596) 和[为什么客户端密码哈希如此不常见?](https://security.stackexchange.com/q/53594)。 (10认同)
  • 为什么这个错误的答案会有这么多的反对:( (4认同)
  • 如果您担心带有HTTPS的MITM,向客户端发送盐分以使客户端可以在将哈希发送回服务器之前对盐分进行盐分有什么意义?似乎毫无意义。也可以只对服务器进行无盐哈希处理,然后使用盐再次在服务器上进行哈希处理。显然,客户端也不可能是客户端盐的生成器,因为下一次登录将是不同的,并且不会计算相同的哈希服务器端。 (3认同)
  • 我想要@gremwell 的答案。如果谷歌不做,我也不做。如果只是为了实用。 (3认同)
  • 所以我真的很喜欢这个答案,但是我想知道是否可能存在*轻微*误报,关于*身份验证密钥*(实际密码的希望是咸的哈希)是如何被"保护"的.当然,这是一个额外的安全层,但是一旦该认证密钥被泄露,它仍然可以被强制强制,因为攻击者将知道用于生成它的算法(因为它在客户端系统上).虽然我完全赞同使用"受保护"一词,但它并不是完全无懈可击的. (2认同)
  • 为什么不在客户端使用简单的哈希并在后端使用加盐哈希呢? (2认同)
  • @Silver我乐观地称它为术语错字.可能意味着"加密/解密"而不是"哈希/解除哈希",就像你说的那样,哈希只是一个方向. (2认同)
  • 可以重写证书的MitM可以重写nonce.或者萨吉德说的话. (2认同)
  • 所以你用随机数加密密钥,然后在服务器上解密它,然后散列它,然后存储散列。稍后,你做同样的事情,除了不是存储散列,而是检查存储中是否存在具有相同用户名的条目,如果有,则检查散列是否相同。或者,根据散列函数,您验证您存储的散列和刚刚通过的散列是否使用相同的密钥(密码)计算。我有这个权利吗? (2认同)
  • 我们应该对用户密码进行哈希处理,因为我们*假设我们的系统将受到损害*。读取数据库只是入侵者获取密码的一种方法,这正是服务器端加盐密码哈希所防止的。如果密码以纯文本形式发送,入侵者可以简单地点击身份验证端点。客户端哈希可防止入侵者嗅探密码并在其他系统中重复使用它们。 (2认同)
  • 此外,即使是大公司也会不小心将密码存储在他们的日志文件中。这就是为什么你不应该通过网络发送密码,而应该只发送散列的另一个原因 (2认同)
  • “确实没有必要知道原始密码是什么。”密码验证怎么样?您实际上并不相信用户创建安全密码,对吗? (2认同)
  • 我相信托马斯试图表达的观点之一是,如果您正在使用的服务受到损害,密码将不会以明文形式发送。他主张进行深度防御,假设即使服务在以后受到损害,密码也不会以明文形式通过网络发送,并且可能会在日志文件、无效服务器配置、缓存等中捕获。尽管服务现在已受到威胁,但电子邮件+密码组合并未受到威胁,从而保护用户免受可能使用相同凭据的其他服务的侵害。 (2认同)

Kie*_*old 22

由于它是通过HTTPS,所以在没有散列的情况下发送密码绝对没问题(通过HTTPS,它不是明文).此外,如果您的应用程序依赖于HTTPS,以保持它的内容的安全,那么它的无用发送它通过HTTPS之前散列密码(即,如果攻击者能够解密方法电线上的数据,你反正旋)

  • @Jader:摆弄数据的任何数量都不会阻止MITM攻击,因为它只能传递任何内容.无论您是传输密码还是哈希都没关系.那是完全不同的事情. (7认同)
  • 这应该不是问题.如果客户端使用代理,则所有代理都将看到HTTPS加密数据.如果您正在谈论中间人攻击,正确配置的证书应该可以防止这种情况发生. (4认同)
  • SSL(HTTPS = HTTP over SSL)的目的是阻止MITM. (2认同)

roo*_*ook 16

不,实际上这将是一个漏洞.如果攻击者能够从数据库中获取哈希值,那么他可以使用它进行身份验证而无需破解它.在任何情况下,用户或攻击者都无法获得哈希密码.

散列密码的重点是添加额外的安全层.如果攻击者能够使用SQL注入或不安全的备份从数据库中获取哈希和盐,那么他必须通过强制查找纯文本. John The Ripper通常用于打破盐渍密码哈希值.

不使用https违反了OWASP Top 10:A9-传输层保护不足

编辑: 如果您在实现中计算a sha256(client_salt+plain_text_password)然后计算服务器端的另一个哈希值,sha256(server_salt+client_hash)那么这不是一个严重的漏洞.但是,它仍然容易被窃听和重放请求.因此,这仍然明显违反了WASP A9.但是,这仍然使用消息摘要作为安全层.

我所看到的最接近https的客户端替代品是javascript密钥交换中的一个难以理解的人.然而,这确实阻止了MITM的主动攻击,因此直到技术性违反了OWASP A9.代码的作者同意这不是HTTPS的完全替代品,但它总比没有好,比客户端散列系统更好.

  • 实际上我会在服务器中再次哈希,所以请编辑你的答案考虑这个场景. (4认同)

Pau*_*ter 8

通过线路发送哈希完全违背了哈希的目的,因为攻击者可以简单地发送哈希并忘记密码.简而言之,一个在明文中使用散列的体验的系统是开放的,只能通过网络嗅探来妥协.

  • 这似乎完全是废话......哈希如何比密码更安全? (2认同)
  • 这仅适用于“哑”哈希。考虑一下:服务器将盐 S 发送到客户端,客户端执行 HASH(S + PASSWORD),然后将其发送到服务器。服务器仅在当前会话中尊重该特定哈希值。攻击者确实可以发送哈希值并忘记密码,但仅限于当前会话。因此它比纯文本更安全。 (2认同)
  • 需要明确的是:当我说"打败哈希的目的"时,我指的是在将密码存储到数据库之前对哈希密码进行通用和安全的实践.然而,该论点认为,发送散列值而不是密码不会在没有额外步骤的情况下增强安全性. (2认同)

小智 6

明文显示的密码永远不会(甚至在使用HTTPS时)离开客户端.它应该在离开客户端之前进行不可逆转的散列,因为服务器不需要知道实际的密码.

Hashing然后传输解决了在多个位置使用相同密码的懒惰用户的安全问题(我知道我这样做).然而,这并不能保护您的应用程序,因为黑客可以通过传输哈希并让服务器接受它来获取对数据库的访问权限(或以任何其他方式获得哈希).

要解决这个问题,您当然可以散列服务器接收的哈希并在一天内调用它.

我在创建基于套接字的Web应用程序中解决问题的方法是,在连接到客户端时,服务器生成一个盐(在散列之前添加随机字符串)并将其存储在套接字变量上,然后传输此哈希给客户.在将数据传输到服务器之前,客户端获取用户密码,散列它,从服务器添加盐并散列整个内容.然后将其发送到服务器,该服务器将此哈希值与哈希值(DB + salt中的哈希值)进行比较.据我所知这是一个很好的方法,但公平地说我没有读过很多关于这个主题的内容,如果我对任何事情都错了,我很乐意纠正:)


pix*_*pax 5

免责声明:我绝不是安全专家,我发帖是希望其他人批评我的立场过于谨慎或需要改进,我会从中学习。话虽如此,我只是想强调,当它离开您的客户端时进行散列并不意味着您不必在将其放入数据库之前在后端进行散列。

两者都做

两者都做,因为:

  1. 传输过程中的散列有助于覆盖传输漏洞,如果 SSL 连接遭到破坏,他们仍然看不到原始密码。就能够冒充授权用户而言并不重要,但它将保护您的用户免遭与电子邮件关联的密码读取。大多数人不遵循最佳实践,并且对许多帐户使用相同的密码,因此这对您的访问者来说可能是一个严重的漏洞。

  2. 如果有人以某种方式能够从数据库读取密码(这种情况确实发生,想想 SQL 注入),他们仍然无法通过我的 API 执行冒充用户的特权操作。这是因为哈希不对称;即使他们知道存储在数据库中的哈希值,他们也不会知道用于创建它的原始密钥,而这就是您的身份验证中间件用于进行身份验证的密钥。这也是为什么你应该总是给你的哈希存储加盐。

诚然,如果他们可以自由地从数据库中读取他们想要的内容,他们可能会造成很多其他损害。

我只是想在这里强调,如果您确实决定在离开客户之前对密钥进行散列,那么这是不够的 - 在我看来,后端散列更为重要,这就是原因:如果有人拦截来自您的流量客户端,然后他们将看到该password字段的内容。无论这是哈希值还是纯文本,都没关系——他们可以逐字复制它来冒充授权客户端。(除非您按照@user3299591 概述的步骤进行操作,我建议您这样做)。另一方面,散列数据库列是必要的,而且实现起来并不困难。