如何通过 HTTP 安全地发送密码?

如果在登录屏幕上用户提交了一个带有用户名和密码的表单,密码将以纯文本形式发送(即使使用 POST,如果我错了请纠正我)。

什么是正确的方法来保护用户和他的密码对第三方谁可能窃听通信数据?

我知道 HTTPS 是这个问题的解决方案,但是有没有办法使用标准的 HTTP 协议(POST 请求)来确保至少一定程度的安全性?(可能以某种方式使用 javascript)

我所关心的是一个页面——这是一个 PHP 生成的登录页面,当然是以 HTML 文件的形式在 HTTP GET 请求中发送给用户的。在服务器和客户端之间没有(@Jeremy Powell)连接,所以我不能创建这样的握手协议。我希望整个过程对用户是透明的-他想提交一个密码,而不是处理加密。

164283 次浏览

您可以使用挑战响应方案。假设客户机和服务器都知道一个秘密 S。然后,服务器可以通过以下方法确保客户端知道密码(而不会泄露) :

  1. 服务器向客户端发送一个随机数 R。
  2. 客户端将 H (R,S)发送回服务器(其中 H 是一个密码杂凑函数,如 SHA-256)
  3. 服务器计算 H (R,S)并将其与客户端响应进行比较。如果它们匹配,服务器就知道客户端知道密码。

编辑:

这里有一个与 R 的新鲜度和 HTTP 是无状态的事实有关的问题。这可以通过让服务器创建一个机密(称为 Q)来处理,即 只有服务器知道。协议是这样的:

  1. 服务器生成随机数 R,然后发送到客户端 H (R,Q)(客户端无法伪造)。
  2. 客户端发送 R,H (R,Q) ,计算 H (R,S) ,并将所有这些发送回服务器(其中 H 是一个密码杂凑函数,如 SHA-256)
  3. 服务器计算 H (R,S)并将其与客户端响应进行比较。然后它取 R 并(再次)计算 H (R,Q)。如果客户机版本的 H (R,Q)和 H (R,S)与服务器的重新计算匹配,则服务器认为客户机已通过身份验证。

需要注意的是,由于客户端无法伪造 H (R,Q) ,因此 H (R,Q)充当 cookie (因此可以实现为 cookie)。

另一个编辑:

之前对协议的编辑是不正确的,因为任何观察到 H (R,Q)的人似乎都能够使用正确的散列重播它。服务器必须记住哪些 R 不再新鲜。我正在连接这个答案,所以你们可以在这里编辑,并制定出一些好的东西。

在 SSL 中使用 HTTP 将使您的生活变得更加轻松,并且您可以轻松地休息。非常聪明的人(至少比我聪明!)多年来一直在仔细研究这种保密通信方式。

HTTPS 之所以如此强大,是因为它使用了非对称加密技术。这种类型的加密不仅允许您创建加密通道,而且还可以验证您正在与正确的人通话,而不是黑客。

下面是 Java 源代码,它使用非对称密码 RSA (由 PGP 使用)进行通信: Http://www.hushmail.com/services/downloads/

我会使用一个服务器端和客户端的迪菲-赫尔曼密钥交换系统,带有 AJAX 或多个表单提交(我推荐前者) ,尽管我在互联网上没有看到任何好的实现。请记住,MITM 总是可能损坏或更改 JS 库。在一定程度上,本地存储可以帮助解决这个问题。

如果您的网站主机允许它,或者您将需要处理敏感数据,然后使用 HTTPS,句号。(这通常是法律所要求的)。

否则,如果你想通过 HTTP 做一些事情,我会这样做。

  1. 服务器将其公钥嵌入到登录页面中。
  2. 客户机填充登录表单并单击提交。
  3. AJAX 请求从服务器获取当前时间戳。
  4. 客户端脚本连接凭据、时间戳和 salt (由模拟数据散列,例如鼠标移动、按键事件) ,并使用公钥对其进行加密。
  5. 提交结果散列。
  6. 服务器解密哈希
  7. 检查时间戳是否足够近(仅允许5-10秒的短时间窗口)。如果时间戳太旧,则拒绝登录。
  8. 将哈希存储20秒。在此间隔期间拒绝登录相同的哈希。
  9. 对用户进行身份验证。

因此,这样密码受到保护,同样的身份验证散列不能重播。

关于会话标记的安全性。这有点难。但是有可能使重用被窃取的会话令牌变得更加困难一些。

  1. 服务器设置一个包含随机字符串的额外会话 cookie。
  2. 浏览器在下一个请求时发送此 cookie。
  3. 服务器检查 Cookie 中的值,如果不同,则销毁会话,否则一切正常。
  4. 服务器再次用不同的文本设置 Cookie。

因此,如果会话令牌被盗,并且其他人发送了请求,那么在原始用户的下一个请求中,会话将被销毁。因此,如果用户主动浏览网站,经常点击链接,那么小偷不会走远与被盗令牌。这个方案可以通过要求对敏感操作(如删除帐户)进行另一个身份验证来加强。

编辑: 请注意,如果攻击者使用不同的公钥设置自己的页面并向服务器发送代理请求,这并不能防止 MITM 攻击。 为了防止这种情况,公钥必须被固定在浏览器的本地存储或应用程序中,以检测这些技巧。

关于实现: RSA 可能是大多数已知算法,但是对于长键来说相当慢。我不知道 PHP 或 Javascript 实现的速度会有多快。但可能有更快的算法。

可以使用 SRP在不安全通道上使用安全密码。这样做的好处是,即使攻击者嗅探了流量,或者破坏了服务器,他们也不能在不同的服务器上使用密码。https://github.com/alax/jsrp是一个 javascript 库,支持通过 HTTP 在浏览器或服务器端(通过节点)保护密码。

安全身份验证是一个广泛的主题。简而言之,正如@jeremy- 鲍威尔所提到的,总是喜欢通过 HTTPS 而不是 HTTP 发送凭证。它将消除许多与安全相关的头疼问题。

TSL/SSL 证书现在很便宜。事实上,如果您根本不想花钱,那么有一个免费的 让我们加密自动证书颁发机构。

您可以进一步使用 Caddyserver.com,它在后台调用 letscrypt。

现在,一旦我们解决了 HTTPS 的问题..。

您不应该通过 POST 有效负载或 GET 参数发送登录和密码。改为使用授权标头(HTTP基本认证方案) ,其构造如下:

  • 用户名和密码组合成一个由 冒号,例如: username: password
  • 生成的字符串使用 Base64的 RFC2045-MIME 变体,但不限于76 Char/line.
  • 然后是授权方法和空格,即“ Basic” 置于编码字符串之前。

来源: Wikipedia: Authorization header 维基百科: 授权头部

这可能看起来有点复杂,但事实并非如此。 有很多很好的库可以为您提供开箱即用的功能。

有几个很好的理由可以说明为什么应该使用 Authorization 头

  1. 这是一个标准
  2. 它很简单(在你学会如何使用它们之后)
  3. 它将允许您在 URL 级别登录,如下所示: https://user:password@your.domain.com/login(例如,Chrome 将自动将其转换为 Authorization头文件)

重要提示:

  • 正如@zaph 在他下面的评论中指出的那样,将敏感信息作为 GET 查询发送不是一个好主意,因为它很可能最终会出现在服务器日志中。
  • 传统上,Authorization头值是一个 base64编码的用户名/密码。Base64不是加密的。原始值可以通过使用简单的 base64-decode 进行路径攻击来获得。

enter image description here

您可以使用 ssl 为您的主机有一个免费的 ssl 项目,如 letscrypt Https://letsencrypt.org/

在这里使用 https 听起来是最好的选择(证书现在并不那么昂贵)。但是,如果 http 是一个需求,您可以使用一些加密-在服务器端加密和在用户浏览器中解密(分别发送密钥)。

我们在实现 Safevia.net-加密时使用的是客户端(发送方/接收方) ,因此用户数据在网络和服务器层都不可用。