不使用 SSL 实现双向密码加密

14
我正在使用基本认证的 Twitter API(不再提供支持)将 Twitter 集成到我的博客评论系统中。但这个和许多其它 Web API 一样的问题是,要做任何有用的事情都需要用户的用户名和密码。我不想处理安装 SSL 证书的麻烦和成本,但也不想以明文形式传输密码。
我的一般问题是:如何在不安全的通道上传输敏感数据?
这是我当前的解决方案,我想知道其中是否存在漏洞:
  1. 在服务器上生成一个随机密钥(我正在使用 PHP)。
  2. 将该密钥保存在会话中,并在一个 JavaScript 变量中输出该密钥。
  3. 在表单提交时,使用Javascript 中的 Triple DES与密钥加密密码。
  4. 在服务器上使用来自会话的密钥解密密码,然后销毁会话。
最终结果是只有加密后的密码被发送到网络,且该密钥只被使用一次且不会与密码一起发送。问题解决了吗?

2
你做不到。SSL很昂贵,因为所有浏览器都信任的第三方已验证您的服务器是特定域名的真实服务器。当攻击者可以迫使用户认为他们的服务器是您域名的主机时,加密就毫无用处,而这种攻击只需要在wifi或以太网网络(图书馆、学校、办公室等)上执行一瞬间即可。请查看Security Now播客的历史记录以了解所有问题,您很快就会发现从某些便宜的人那里购买SSL证书更容易和更便宜。 - Abhi Beckert
13个回答

34
  1. 在服务器上生成一个随机密钥(我使用php语言)。
  2. 将密钥存储在会话中,并在javascript变量中输出密钥。
  3. 在表单提交时,使用javascript的Triple DES算法和密钥来加密密码。

这样做可以避免在网络传输中明文传输密码,但需要在网络传输中明文传输密钥,这会使窃听者有可能破译密码。

就像之前提到的一样,不要试图自己设计加密协议!已经有为此类问题创建、经过专业人士评审、被反复测试、被黑客尝试入侵并受到安全社区认可的成熟协议,请使用它们! 没有一个人能够比整个加密与安全社区共同合作得到更好的方案。


9
+1 表示“不要试图自己制定加密协议!”,意思是支持这个观点,建议不要尝试自己设计加密协议。 :D - Jalal

10

您的方法存在缺陷——如果有人拦截了密钥传输以及用户的加密回复,他们就可以解密回复并获取用户的用户名/密码。

然而,有一种安全地在不安全的媒介上发送信息的方法,只要这些信息在传输过程中无法被修改,这就是所谓的迪菲-赫尔曼算法。基本上,两个参与者根据他们的对话计算共享密钥用于加密数据——但是观察者没有足够的信息推断出密钥。

然而,设置客户端和服务器之间的会话可能会比简单地将SSL应用到您的站点要棘手得多,并且需要更多的时间。您甚至不必为此支付费用——您可以生成自签名证书来提供必要的加密。这不会防止中间人攻击,但迪菲-赫尔曼算法也无法防止。


只要信息在传输过程中不能被修改,那么就几乎不可能在没有SSL的HTTP连接上实现。轻松地修改正在传输的信息。 - Abhi Beckert

6
您的服务器上不需要证书,是否与未经身份验证的服务器通信取决于客户端。仍然可以执行密钥协商以建立私有通道。但是,向未经身份验证的服务器发送私人凭据是不安全的,这就是为什么在实践中不会看到SSL以这种方式使用的原因。
回答您的一般性问题:您只需发送它。我认为您真正的一般性问题是:“如何通过不安全的通道发送敏感数据并保持其安全?” 您无法做到这一点。
听起来您已经决定安全不值得每月10-20美元的证书费用,并且为了保护Twitter密码,这可能是正确的。那么,为什么要花时间提供安全的幻象呢?只需向用户明确说明他们的密码将以明文形式发送,并让他们自己选择即可。

2
API和OAuth
首先,正如其他人所说,您不应该使用用户的密码来访问API,而应该获取OAuth token。这将允许您代表该用户行事,而无需知道他们的密码。这是许多API使用的常见方法。
密钥交换
如果您需要解决更一般的通过不安全连接交换信息的问题,则有几个键交换协议,如其他答案中提到的那样。
总的来说,密钥交换算法对于窃听者来说是安全的,但由于它们没有验证用户的身份,因此容易受到中间人攻击。
来自维基百科关于Diffie Hellman的页面:
在原始描述中,Diffie-Hellman交换本身并不提供通信各方的身份验证,因此容易受到中间人攻击。中间人可以与Alice和Bob分别建立两个不同的Diffie-Hellman密钥交换,有效地伪装成Alice与Bob,反之亦然,从而允许攻击者解密(并读取或存储)它们之间传递的消息,然后重新加密。一种用于相互认证通信各方的方法通常需要用来防止这种类型的攻击。变体的Diffie-Hellman,例如STS,可以用于避免这些类型的攻击。

即使是STS在某些情况下也是不安全的,其中攻击者能够将自己的身份(签名密钥)插入到发送方或接收方的位置。

身份和认证

这正是SSL旨在解决的问题,通过建立一系列“受信任”的签名机构的层次结构,这些机构已经理论上验证了谁拥有一个域名等信息,连接到网站的人可以验证他们确实正在与该域名的服务器通信,而不是与中间人进行通信。
您可以创建自签名证书,这将提供必要的配置以加密连接,但出于与未经身份验证的Diffie-Hellman密钥交换相同的原因,它无法保护您免受中间人攻击。
您可以从https://www.startssl.com/获得有效期为1年的免费SSL证书-我用它们来管理我的个人网站。它们并不像其他服务那样“受信任”,因为它们只对申请者进行自动检查,但是它是免费的。在英国,也有很少花费(从123-Reg每年10英镑)的服务。

2
那么这样更安全吗?即使你已经保护了浏览器<>服务器,那么互联网上的其他部分(你的服务器<>Twitter)呢?
在我看来,要求用户输入另一个服务的用户名和密码并期望他们这样做是不可接受的。如果你非常关心安全性,那就在它们改正错误并重新启用OAuth之前不要集成它们。(它们曾经支持过OAuth,但几个月前禁用了它。)
与此同时,为什么不提供OpenID呢?每个Google、Yahoo!、VOX等账户都有一个。人们可能不知道,但他们已经拥有OpenID的机会真的很高。请查看这个列表以了解我的意思。

请问您能解释一下第二段第一句话的意思吗?只要您信任询问您用户名和密码的网站,为什么会不可接受呢?它可以减轻密码疲劳,并且如果实现得安全(HTTP Secure、SSL/TLS等),它可以非常有用。此外,这通常是 StackOverflow 的做法,例如允许我们使用 Google 账户。最后,仍有大量电子邮件提供商不支持 OpenID 和 OpenID Connect。 - gouessej

2
当密钥在客户端和服务器之间发送时,它是明文的,容易被拦截。将其与密码的加密文本结合起来,密码就会被解密。
Diffie-Hellman是一个很好的解决方案。如果你只需要验证身份,而不实际传输密码(因为密码已经存储在服务器上),那么可以使用HTTP摘要认证或其变体。

1
客户端JavaScript安全的问题在于攻击者可以修改传输中的JavaScript,使其简单地返回输入,从而使您精心设计的安全措施失去作用。解决方案:使用浏览器提供的(即未传输的)RSA。据我所知,目前还不可用。

1

我实现了一种不同的方法

  1. 服务器:将用户名和密码哈希存储在数据库中
  2. 服务器:使用表单发送一个挑战来请求密码,在会话中与时间戳和客户端IP地址一起存储
  3. 客户端:哈希密码,连接挑战|用户名|密码哈希,再次哈希并将其发布到服务器
  4. 服务器:验证时间戳、IP,进行相同的连接/哈希并进行比较

这适用于密码传输。对于数据的使用意味着使用最终的哈希作为明文的加密密钥,并生成随机初始化向量以与密文一起传输到服务器。

有关此事的任何评论吗?


0

我有一个类似的问题(想要在表单中加密数据而不需要支付SSL证书费用),所以我进行了一些搜索,找到了这个项目:http://www.jcryption.org/

我还没有使用过它,但它看起来很容易实现,所以我想在这里分享一下,以防其他人也在寻找类似的东西,并像我一样发现了这个页面。


现在我已经使用了这个项目,我可以说它很棒,并且非常容易集成到 PHP 项目中。当然,它并不能真正为您提供100%的保护,[请参见此处](http://www.matasano.com/articles/javascript-cryptography/)但如果您只是想找一种方法来增加保护,而不是以明文形式发送表单元素...这是一个不错的选择。 - Dsyko

0

致 OLI

在你的方法中,例如我和我的同事在同一子网中,使用相同的路由器,因此我得到与我的同事相同的IP地址。我在浏览器中打开相同的URL,因此服务器使用相同的IP生成时间戳,然后我使用TCP/IP转储从我的同事连接中嗅探散列或非散列密码。我可以嗅探他发送的所有内容。因此,我还有他表单中的所有哈希值,你也有时间戳(我的)和相同的IP。因此,我使用POST工具发送所有内容,嘿,我已经登录了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接