身份验证方法

时间:2009-05-07 14:22:26

标签: java python authentication encryption hash

我正在编写一个服务器 - 客户端应用程序来接收用户消息并将其发布。

考虑认证方法。

  1. 非对称加密,可能是RSA。
  2. 哈希(盐+密码+'msg'+'用户ID'),SHA256
  3. HMAC,SHA256。似乎比方法2更安全。还涉及散列密码和消息数据。
  4. 使用双面存储的静态密码对'msg'进行对称加密,可能是AES。
  5. 无需加密,因为msg无论如何都会在线发布。所以我更倾向于使用HMAC或PKI方法。

    我正在使用java发送请求(包括要实现的任何身份验证方法) www.mysite.com/foo?userid=12345&msg=hello&token=abc1234

    服务器端的python接收请求并确保请求来自有效用户。

    问题在于整合,并确保双方都了解彼此的身份验证令牌。这对我来说是个很重要的因素。并且还考虑了两种语言可用的库的可用性。

    或者我可以选择将服务器端重写为java。 (为什么不用python?客户端应用程序需要在java中)

    您怎么看?


    编辑:我不会将此视为Web应用程序。该应用程序不提供任何网页。大多数操作与Web无关。只是客户端 - 服务器通信通过互联网。通过HTTP发送POST / GET是我认为最简单但不安全的方法。随意建议我任何其他选择。

    SSL是一种安全的加密方式。但它并不能阻止攻击者向服务器发送作为用户强加的消息。任何人都可以启动HTTPS连接。并且通信的内容不需要加密。无论如何,它将由服务器在线发布。我需要的是一种验证邮件和发件人的方法。

    目前我依赖于HMAC算法。 RSA会更安全,但它也会带来更多开发人员的努力。会看到它是怎么回事。

    谢谢。

4 个答案:

答案 0 :(得分:2)

您不能只使用标准SSL套接字来保护连接,使用密码验证用户,然后发送要发布的消息吗?如果客户端不多,您甚至可以使用自签名证书并将其放在客户端应用程序的KeyStore中,这样您就不需要从Verisign或其他任何人那里购买证书。

如果您在服务器上存储用户的密码哈希(因为我认为您应该如何验证用户的密码),那么您可以先在客户端重现该哈希值(让我们假设您使用哈希用户+传递)然后将其附加到消息并散列结果。您将用户ID,哈希和消息发送到服务器。

在服务器端,您收到一个带有用户ID的请求,您检索用户的密码(服务器只存储了用户+密码的散列),您将其附加到消息并再次散列,并将其与请求中的哈希值。如果匹配,则用户可以发布消息。

哦,你应该使用HTTP POST,而不是在URL上发送数据。服务器不应接受发布请求的URL上的数据。

答案 1 :(得分:1)

好的,首先,考虑的选择就是沿着“企业解决方案”路线进入标准PKI市场:从Veri $ ign等自己购买证书并使用无聊的旧HTTPS(或至少TLS,基础协议)。然后从客户端发送数据(或多或少)是轻而易举的,并且在您选择用于解释另一端的事物的任何语言中都会有一个标准库。我实际上认为HTTPS / TLS和整个证书基础架构是一个复杂的空间浪费,适用于您知道正在与之通信的服务器以及您想知道要使用哪种加密系统的应用程序。但是“开箱即用”的库的可用性意味着可能让你快速启动和运行,因此绝对值得考虑这种或那种方式。

原则上,您不需要PKI颁发的证书来使用HTTPS / TLS。但实际上,花费少量资金比尝试并说服标准库接受自发证书更容易。 (一般来说,使用HTTPS库可能只是意味着你最终将2天的“编程我的加密系统”问题变成了为期2天的“为什么这个黑盒子不接受我的证书”问题 - 它也有点依赖你喜欢解决什么问题...)

即使您不使用HTTPS / TLS,您也可以阅读规范,了解它如何克服某些安全威胁(以及这些威胁是什么)。

好的,那么接受你的观点:

  • 为了清楚起见,您不需要证书或PKI来使用RSA或其他非对称加密。 PKI(试图)解决了客户端需要与“神秘”服务器通信的问题,当服务器说“这是我的公钥”时,它无法信任。如果您正在编写专用客户端,并且事先知道您正在与哪个服务器通信,那么您只需向您的客户分发公钥即可。客户端知道它正在与正确的服务器通信,因为如果不是,该服务器将无法理解使用该公钥加密的内容。
  • 使用“原始”哈希时需要注意的主要事项是它们容易受到扩展攻击。因此,如果您发送“a | b | c”加上该数据的哈希码,攻击者可以计算出“a | b | c | d”的哈希码(因此在您的示例(2)中,它们可以替换“ userid“for”useridX“并根据您为”a | b | c“提供的哈希码为此计算出新的哈希码。 HMAC计划解决了这个问题。
  • 无论如何,如果你使用“原始”加密工具,仍然使用标准库,因为他们会考虑一些安全问题。例如,对于RSA,您必须小心使用填充(请参阅我在RSA encryption in Java上编写的一些信息以及它所在的加密部分 - 这可能对您有意义)。在生成任何加密密钥时,您需要注意“随机数据的来源”。
  • 您不必在密码上建立AES加密密钥(如果您这样做,请阅读基于密码的加密方案:密码通常具有很少的熵,因此您需要采取额外措施来尝试防范此问题)。但我会采用更标准的方法来使用密码来验证连接,并且作为身份验证的一部分,协商一个随机的AES密钥。
  • 确保您正在解决方案中的重放攻击问题(通常,客户端和服务器应在通信开始时互相发送随机的“随机数”),并且通过该连接进行身份验证和将来的通信将取决于nonce)。

答案 2 :(得分:1)

让我在您的提案中添加一些随机的想法/评论。

  1. RSA:由于您主要对身份验证感兴趣,我假设您要使用RSA签名。这意味着每个用户都需要自己的私钥。对我来说听起来有点像矫枉过正,特别是当用户和服务器已经共享共同的秘密(即密码)时。
  2. 使用SHA256是一种很好的方法。我有一些问题要理解你为什么要加盐,因为盐通常用来避免攻击者预先计算字典的哈希值。需要明确的是:双重攻击是一个问题。攻击者可能会尝试使用字典中的所有密码来散列消息。只是他必须为每个用户重新进行此攻击,并且无法重用预先计算的值。一种做出这种攻击的方法 更难以称为密钥强化,例如通过重复哈希结果n次 并因此迫使攻击者在字典攻击期间执行更多工作。
  3. 我完全同意HMAC优于SHA-256。毕竟HMAC是为验证而设计的。我不确定为什么要在计算HMAC之前散列消息。 HMAC为您做到了这一点。
  4. 加密并不总是提供身份验证。这特别是在攻击者学习明文的情况下,就像他在你的情况下那样。他可能能够利用加密模式的属性来操纵密文并确切知道所得到的明文将如何显示(例如,CBC模式允许这些操作)。您之前的提案(HMAC)更可取。
  5. 最后,如果您可以在用户和服务器之间建立SSL连接,正如其他人所说:这将是一个更安全的解决方案,因为即使上面提到的诅咒攻击也不可能。

答案 3 :(得分:0)

RSA协议通常用于为更快的加密手段设置密钥交换。这就是SSL的工作原理。

如果您的应用程序的安全性要求非常敏感,以至于您需要PKI,那么应该说(如果您需要在SO上询问它),那么它可能是您不应该做的事情。尝试做(假设通常成功攻击安全通道攻击实施的弱点)。

正如Chochos所建议的那样,简单地使用Java中的现有SSL基础设施和服务器设置安全的https连接,然后只是将用户密码从客户端传递到服务器有什么问题?