作为密码更新过程的一部分,通过 SSL 发送纯密码是否不好?

信息安全 Web应用程序 密码管理 爪哇
2021-08-18 03:49:09

我正在开发的 Web 应用程序是 100% 受 SSL 保护的(或者更确切地说是 TLS,因为它现在被称为......)。该应用程序最近已由一家安全公司审核。我大多同意他们的结果,但有一件事引发了激烈的辩论:

作为用户密码更改过程的一部分,用户必须提供旧密码和新密码两次——这并不罕见。除此之外,新密码必须符合密码策略(最小长度,yadda yadda)。

该应用程序是通过 Vaadin 实现的,它使用小的 AJAX 消息来更新 UI。应用程序的整个逻辑都存在于服务器上。这意味着密码更改表单的所有验证都发生在服务器上。为了验证表单,旧密码和两个新密码(当然应该匹配)都必须发送到服务器。如果有任何错误(旧密码错误、新密码不匹配、新密码不符合密码策略),用户会收到错误消息。不幸的是,作为同步过程的一部分,Vaadin 将所有表单数据再次发送回客户端——包括旧密码和新密码。

由于这一切都是通过 SSL 发生的,我从来没有考虑过,但安全公司认为这是最严重的安全风险。请注意,安全公司眼中的问题不是数据被发送到服务器,而是服务器在其响应中包含数据以防验证失败因此,我们当前的解决方案是在验证失败时清空所有字段。这会导致糟糕的用户体验,因为如果密码反复与密码策略不匹配,用户必须一次又一次地填写三个文本字段。

我是否天真地认为这太过分了?我的意思是,如果攻击者破坏了加密,他们无论如何都可以访问整个流量。


编辑:关于肩部冲浪,我想明确指出,没有任何密码会回传给用户所有输入字段都是正确的密码字段,仅显示占位符但不显示实际字符。

4个回答

实际上,我认为清除字段是更好的用户体验。假设密码字段充满了星号,则用户在重新输入密码时无论如何都会删除整个字段。

此外,您还面临新的安全风险。存在 XSS、肩部冲浪以及任何时候发送密码的可能性,这通常会增加您的风险。

如果我输入了不正确的内容,我从未访问过保持密码字段填写的网站。唯一填写的字段是电子邮件字段,可能还有地址/电话号码。

你总是不得不假设最坏的情况,如果你能堵住一个洞,就这样做。我不认为安全审计员是最重要的,特别是因为这是一个真正不存在的用户体验问题的简单解决方案——如果你发回他们的密码并显示它们而不将每个字符更改为星号,那么你肯定有安全问题。有人应该看到他们输入的密码的唯一一次是他们选择了一个允许他们暂时看到它的选项。

最好有一个密码只输入不输出的策略。这是一种实用的方法,也是朝着安全的正确方向迈出的良好一步,而且成本很低。

如果单击“查看源代码”,则任何密码输出也将以纯文本形式显示,这意味着周围的任何肩冲浪者都可以查看密码。

如果只是要求用户重新输入他们的原始密码、新密码和确认,那么这不是一个巨大的 UI 缺陷。如果它是一个巨大的页面并且其他字段的验证导致密码框为空白,那么这可能会让用户每次重新输入他们的三个密码很烦人,并且可能导致一些用户简单地输入qwerty什么的。如果是这种情况,我会将密码字段移动到另一个页面,以便可以单独输入和验证它们。

将输入回显给客户端总是会引起跨站点脚本 XSS 的怀疑。但在你的情况下,我认为这是一种过度反应,因为输出是瞬态的,除了输入它的人之外,永远不会显示给其他任何人。你试过<script>alert(document.cookie);</script>作为密码吗?

您可以通过更改整个密码和 Ajax 自行调用来与您的审计员玩游戏,从不清除表单或更改页面。您只需要使用错误代码进行响应,相应地调整 UI。有点像这样:

  1. 在表格中询问当前密码、新密码和重复密码
  2. 用户单击“更改密码”,向服务器发出 Ajax 请求。表单保持不变,并带有一些动画 gif-in-a-div 让用户等待
  3. 如果更改失败,服务器会以错误代码响应(不够复杂,新的和重复的不匹配等)
  4. 如果它们不匹配,请清除新字段和重复字段

请记住,每次不成功的尝试都会使旧密码变旧。旧密码用于确保合法用户进行更改。您“重用”它的次数越多,确定性就越弱。您应该在 N 次尝试失败后(或 N 秒后)清除所有内容。

我认为将密码发送回客户端被认为是不安全的原因是因为客户端可能会缓存页面,这意味着在用户本地驱动器的某处存储了一个纯文本版本的密码。点击后退按钮或解析缓存可能会泄露密码。这在公共机器上尤其糟糕。

此外,在某些有效场景中,您可能想要执行 OP 的建议。例如,如果您有一个带有验证码的注册屏幕,那么每次验证码失败时让用户重新输入两个密码可能会过于烦人。但是,如果您的网站足够重要以至于需要进行安全审核,那么您最好避免这种情况,而是考虑让您的验证码更容易。