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


115

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

所以问题是,保护用户及其密码免受可能窃听通信数据的第三方的正确方法是什么?

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

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

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

谢谢。


1
如果没有客户端使用加密技术,您可能将无法完成此任务,但是用户不必看到这样的过程。他只需输入密码,您的PHP生成的代码(例如javascript)即可为您处理所有密码。
杰里米·鲍威尔

13
您描述的问题是发明HTTPS的原因。如果您将秘密发送给客户端以对密码进行加密,则窃听者将能够对其进行嗅探并在回程中解密密码。
jnoss

1
因此,您的建议中的S只能是密码(或以任何方式组合的用户名和密码),因为这是用户拥有的唯一“秘密”。我对么?因此解决方案如下:-服务器为HTML页面提供了一个隐藏的表单字段R-用户输入密码,并且在发送密码之前,javascript计算H(R,S)并将其发送到服务器,也许甚至通过使用AJAX-服务器计算H(R,S)并将其与接收到的内容进行比较,然后向ajax请求发送响应,以验证身份验证是否通过
-javascript

2
@jeremy powell-尽管您所描述的是很常见的做法,但它也容易受到中介机构的攻击,这些中介机构可以从标题中嗅探cookie并通过重用cookie来冒充用户。除非您使用HTTPS,否则很难防范中间人攻击
jnoss

1
对于以后遇到这个问题的人:登录后,您还需要保护会话cookie。(因此:使用HTTPS确实容易得多。)
Arjan 2010年

Answers:


66

将HTTP与SSL配合使用将使您的生活更加轻松,并且您可以放心一些非常聪明的人(至少比我聪明!)对这种机密通信方法进行了多年审查。


14
...和“但是我必须支付SSL证书!” 这不是有效的投诉,因为这些天您只需30美元即可获得。您的数据真的不值得保护30美元吗?
caf

3
如果您订阅的虚拟主机不支持添加SSL证书怎么办?
Calmarius

89
@Calmarius-然后您转到真正的虚拟主机
BornToCode 2013年

3
@BornToCode从技术上讲,这意味着您需要一个专用的IP,并且需要拥有服务器硬件(或至少一个VPS)才能使用HTTPS。共享的Web主机不能执行HTTPS,除非整个服务器都受到主机所有者证书的保护。
Calmarius 2013年

6
共享的虚拟主机当然可以使用en.wikipedia.org/wiki/Server_Name_Indication
Brian Minton 2014年

39

安全身份验证是一个广泛的主题。简而言之,就像@ jeremy-powell提到的那样,始终倾向于通过HTTPS而不是HTTP发送凭据。这将消除许多与安全性相关的麻烦。

目前,TSL / SSL证书非常便宜。实际上,如果您根本不想花钱,那么可以免费使用letencrypt.org-自动证书颁发机构。

您可以更进一步,并使用caddyserver.com,它在后台调用letencrypt。

现在,一旦我们摆脱了HTTPS的束缚...

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

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

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

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

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

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

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

在此处输入图片说明


11
将凭据(密码)作为GET参数发送的问题在于,用户/密码对可能最终会出现在服务器日志中,这不是一个好主意。最好在POST中发送凭据。
zaph '16

啊...一点也不。您正在查看的屏幕截图已修改,以说明浏览器中正在发生的情况。当您按下Enter键时,浏览器将转换您的url,创建一个Authorization标题。随它去吧。日志会提醒您干净。当然,如果您从服务器拨打电话(如果您担心这种情况),那么您当然应该以编程方式生成标头。
FullStackForger

您无法记录看不到的内容。username:password@url从浏览器转换为:url+ Authorization请求标头。至于GET查询...就像我说的那样,请使用Authroziation标头。这个比较好。
FullStackForger

2
您没有解决问题的重点:保护敏感数据免受中间人的窃听。重点不是找到一种替代和/或更标准化的方式来传递凭据,而是通过不安全的通道来保护它们。
咕咕之王

3
应该强调的是,该解决方案仅在您已经使用TLS / SSL加密连接的情况下才有效。base64不加密。
苏格兰,

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不再新鲜。我正在回答这个问题,以便你们可以对此进行修改并制定出一些不错的东西。


+
1-

10
不会阻止人处于中间或冒充他人的攻击。例如通过wifi。IMO似乎会给人一种错误的安全感。
Tom Hawtin-大头钉

2
这样可以防止被动攻击,但是中间人仍然可以攻击。
道格拉斯·里德

7
另外,它要求服务器知道原始密码。
道格拉斯·里德

3
不要重新发明加密货币!(生产中)
bryanph

11

如果您的虚拟主机允许,或者您需要处理敏感数据,请使用HTTPS句号。(法律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实现的速度有多快。但是可能有更快的算法。


在这种情况下,密码是否真正受到保护?有人可以嗅出发送的内容并使用公钥解密,然后在以后使用时更新时间戳吗?我想念什么吗?
michaellindahl 2014年

@michaellindahl非对称加密意味着只能使用永不离开服务器的私钥来解密事物。公钥只能用于加密。
Dan Pantry 2015年

2
浏览器和服务器之间的计算机可以更改登录页面上的公钥。
Antti

感谢您分享您的方法,我发现了很多有趣的东西。发送凭证时添加的时间戳很不错!关于使用额外的会话cookie(其值为随机字符串)的事情的一个问题:就像仅用于下一个请求的令牌一样?
维克多

4

我会使用带有AJAX或多种形式的提交(我建议使用前者)的服务器端和客户端Diffie-Hellman密钥交换系统,尽管我在互联网上看不到任何良好的实现。请记住,MITM总是会损坏或更改JS库。本地存储可以在一定程度上帮助解决此问题。


4

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


1

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

这是使用非对称密码RSA(PGP使用)进行通信的Java源代码:http : //www.hushmail.com/services/downloads/


0

您可以将ssl用作主机,有一个免费的ssl项目,例如letsencrypt https://letsencrypt.org/


2
检查有问题的第三句话。(另外,请务必阅读其他答案,以确保您没有添加细节较少的重复内容。)
Nathan Tuggy

0

在这里使用https听起来是最好的选择(如今,证书并不那么昂贵)。但是,如果需要http,则可以使用某种加密方式-在服务器端进行加密,然后在用户浏览器中进行加密(单独发送密钥)。

我们在实施safevia.net时使用了该方法 -加密是在客户端(发送者/接收者)端完成的,因此用户数据在网络或服务器层均不可用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.