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

Kor*_*tak 111 security encryption passwords http plaintext

如果在登录屏幕上用户使用其用户名和密码提交表单,则密码将以纯文本形式发送(即使使用POST,如果我错了也请更正).

那么问题是,保护用户及其密码的正确方法是针对可能正在窃听通信数据的第三方?

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

编辑 我可能遗漏了一些重要的事情.

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

谢谢.

Jer*_*ell 63

使用HTTP和SSL将使您的生活更轻松,您可以放心,非常聪明的人(至少比我聪明!)多年来仔细检查了这种保密通信方法.

  • @Calmarius - 然后你转移到一个真正的虚拟主机 (83认同)
  • ......和*"但我必须支付SSL证书!!"*不是有效的投诉,因为这些天你可以以30美元的价格获得它们.您的数据真的不值30块钱来保护吗? (12认同)
  • 共享的webhosts当然可以使用http://en.wikipedia.org/wiki/Server_Name_Indication来执行https (5认同)
  • 如果您订阅的虚拟主机不支持添加SSL证书怎么办? (3认同)
  • @BornToCode从技术上讲,您需要拥有专用IP,并且您需要拥有服务器硬件(或至少是VPS)才能使用HTTPS.共享的Web主机无法执行HTTPS,除非整个服务器受主机所有者的证书保护. (3认同)
  • @BRianMinton你100%正确.我运行一个托管多个域的linode,其中只有一些拥有SSL,一些在非标准端口上运行SSL,等等.这也很容易在非vps上完成,因为它只是抛出几行到有问题的域的apache配置. (3认同)
  • 值得一提的是,letscrypt.org 是一个非营利组织,其目标是向每个人提供免费的 SSL 证书。 (3认同)

Ful*_*ger 30

安全认证是一个广泛的主题.简而言之,正如@ jeremy-powell所提到的,总是倾向于通过HTTPS而不是HTTP发送凭据.它会消除许多与安全相关的麻烦.

如今,TSL/SSL证书相当便宜.事实上,如果你根本不想花钱,那就有免费的letsencrypt.org - 自动证书管理局.

你可以走一步,并使用caddyserver.com在后台调用letsencrypt.

现在,一旦我们将HTTPS取消了......

您不应通过POST有效负载或GET参数发送登录名和密码.请改用Authorization标头(基本访问认证方案),其构造如下:

  • 用户名和密码组合成一个以冒号分隔的字符串,例如:username:password
  • 结果字符串使用Base64的RFC2045-MIME变体进行编码,但不限于76个字符/行.
  • 然后将授权方法和空格即"基本"放在编码的字符串之前.

来源:维基百科:授权标题

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

您应该使用Authorization标头有几个很好的理由

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

重要提示:
正如@zaph在下面的评论中指出的那样,将敏感信息作为GET查询发送并不是一个好主意,因为它最有可能最终出现在服务器日志中.

在此输入图像描述

  • 将凭证(密码)作为GET参数发送的问题是用户/密码对可能最终会出现在服务器日志中,这不是一个好主意.最好在POST中发送凭据. (10认同)
  • 需要强调的是,只有在使用TLS/SSL加密连接时,此解决方案才有效.base64不加密. (3认同)
  • 您没有解决问题的重点:保护敏感数据免受中间人窃听.重点不是找到传递凭证的替代和/或更标准化的方法,而是通过不安全的渠道保护它们. (2认同)

Jer*_*ell 14

您可以使用质询响应方案.假设客户端和服务器都知道秘密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不再新鲜.我正在回答这个问题,所以你们可以编辑这个并找出一些好的东西.

  • 不会阻止中间人或冒充攻击.例如通过wifi.似乎这样只会给人一种虚假的安全感,IMO. (10认同)
  • 它还要求服务器知道原始密码. (7认同)
  • 不要重新发明加密!(在制作中) (3认同)
  • 这可以防止被动攻击,但是中间人仍然可以攻击. (2认同)

Cal*_*ius 11

如果您的webhost允许,或者您需要处理敏感数据,请使用HTTPS,period.(法律经常要求afaik).

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

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

因此,密码受到保护,无法重播相同的身份验证哈希.

关于会话令牌的安全性.那有点难了.但是有可能重新使用被盗的会话令牌.

  1. 服务器设置一个包含随机字符串的额外会话cookie.
  2. 浏览器在下一个请求时发回该cookie.
  3. 服务器检查cookie中的值,如果它不同则会破坏会话,否则一切都没问题.
  4. 服务器使用不同的文本再次设置cookie.

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

编辑:请注意,如果攻击者使用不同的公钥设置自己的页面并代理对服务器的请求,则这不会阻止MITM攻击.为防止出现这种情况,必须将公钥固定在浏览器的本地存储中或应用程序内以检测这些技巧.

关于实现:RSA可能是最常见的算法,但对于长密钥来说它很慢.我不知道PHP或Javascript实现的速度有多快.但可能有更快的算法.

  • 浏览器和服务器之间的计算机可以更改登录页面上的公钥. (2认同)

Bri*_*ton 6

您可以使用SRP通过不安全的通道使用安全密码。优点是,即使攻击者嗅探流量或破坏服务器,他们也无法在其他服务器上使用密码。https://github.com/alax/jsrp是一个 javascript 库,支持在浏览器或服务器端(通过节点)通过 HTTP 安全密码。