我的服务器和客户端之间有 TLS 连接。我没有证书,所以连接容易受到中间人攻击。
我担心攻击者可以拦截密码哈希并使用它在我的应用程序中验证自己。
传输密码哈希的最佳方式是什么?使用服务器随机数或客户端随机数?我应该使用什么哈希算法?
我的服务器和客户端之间有 TLS 连接。我没有证书,所以连接容易受到中间人攻击。
我担心攻击者可以拦截密码哈希并使用它在我的应用程序中验证自己。
传输密码哈希的最佳方式是什么?使用服务器随机数或客户端随机数?我应该使用什么哈希算法?
您应该查看Certificate pinning。
这有效地允许您信任您的自签名证书,并且该服务器证书仅来自您的客户端,通过对证书的公钥进行硬查找。因此,不遵循授权链(这是自签名证书失效的地方),而是由客户端应用程序验证公钥以直接受信任。
您不应该查看散列或应用程序层上的任何其他内容,因为它天生就容易受到 MITM 攻击。
你不能。
如果您无法验证服务器并建立安全通道,则没有安全的方式来传输它。如果您无法对服务器进行身份验证,那么您就无法确定您是在与服务器交谈还是与攻击者交谈。因此,即使您使用 TLS 建立安全通道,它也根本无法保护您,因为您可能正在与攻击者交谈,同时认为您正在与服务器交谈。
证书是必不可少的。如果没有它,或者对服务器的公钥有一些了解,你就不能确定你真的在与服务器通信,因为攻击者可能会充当你和服务器之间的中间人。
TLS 使用 Diffie-Hellman 进行密钥交换。如果您查看维基百科页面的安全部分,您会发现以下攻击正是您容易受到的攻击。
在最初的描述中,Diffie-Hellman 交换本身不提供通信方的身份验证,因此容易受到中间人攻击。Mallory 可以建立两个不同的密钥交换,一个与 Alice,另一个与 Bob,有效地将 Alice 伪装成 Bob,反之亦然,允许她解密,然后重新加密它们之间传递的消息。
结论
您需要有一个有效的证书才能对服务器进行身份验证,否则您将容易受到中间人攻击。实现此目的的一种简单方法是将服务器证书包含在您的应用程序中,这也称为证书固定。
将您自己创建的根 CA 证书与您的应用程序捆绑在一起,并将其配置为拒绝所有不受信任的证书。如果您只使用自己的 CA 证书,这可以说比依赖普通 CA 更安全,因为 CA 过去曾被攻击者入侵,并且还受政府当局和政治的影响。
滚动您自己的身份验证方案是鲁莽的,并且几乎可以保证不如简单地使用带有捆绑证书的 TLS 安全。
由于其他人已经提到了 TLS 身份验证以及针对该问题可以采取的措施,因此我将只关注:
传输密码哈希的最佳方式是什么?
MITM 是您的场景中的威胁之一。另一个可能(也很常见)的威胁是数据泄露。您必须考虑数据库可能受到威胁的情况,并且还必须在服务器端采取必要的预防措施。在客户端散列密码不是一个好主意,除非您不信任服务器的密码,并且您在服务器上再次对它们进行散列。我想您的情况并非如此,因为服务器是您自己的。
如果客户端发送的密码哈希按原样存储在数据库中,则攻击者可以通过将数据库中的哈希密码按原样发送给服务器来冒充所有用户。在这种情况下,散列密码将仅用作秘密访问令牌。阅读本文了解更多详情。
我应该使用什么哈希算法?
一些好的散列函数(用于在服务器上存储密码)包括 bcrypt、scrypt 和 PBKDF2。看看Thomas Pornin 的精彩回答,了解为什么这些更好。基本上,如果使用得当,这些功能将使攻击者的任务在数据泄露的情况下变得更加困难。