我的基本用户身份验证方法有什么问题吗?

时间:2012-08-30 17:44:14

标签: security google-app-engine session authentication

在安全性和身份验证以及大多数其他客户端 - 服务器通信方面,我都是一个新手。我正在尝试做的很简单,如果可能的话,避免引入第三方框架和类来完成这项工作。 (我正在使用带有Python的Google App Engine)

用户通过移动应用程序(iOS)登录该服务一次。登录后,用户会发出许多请求,以获取消息,朋友,状态等信息。因此,每次应用程序与服务器通信,而不是发送该用户的电子邮件和密码进行身份验证时,我们将发送一个会话ID。到目前为止,这只是我对系统的理解。

我想出了一个非常简单的方法,对我来说似乎它会工作得很好,但是缺乏经验我可能看不到很多东西。这样做会有什么问题:

  1. 在设备上,用户键入电子邮件/密码,凭据将发送到服务器并进行验证,一旦通过身份验证,就会生成一个随机数。此随机数在User模型上存储为IntegerProperty,名称为session_number。

  2. session_number被发送到用户的设备并被保存。现在,只要用户连接到服务器以获取请求,session_number 以及用户的整数ID号就会被发送到服务器。我们获得该userId的User实体,现在我们比较user.session_number == incoming_session_number的值。如果他们匹配,我们很好,否则错误。

  3. 如果用户注销,我们会从数据存储中清除session_number。

  4. 这里唯一的另一个问题是当用户从多个设备登录时如何处理?每个设备应该存储自己的session_number吗?

2 个答案:

答案 0 :(得分:4)

除了我关于重新发明轮子的评论之外;我在这个理论中看到的主要问题是它完全受到重播攻击的影响。

例如,给定ID为99且会话ID / cookie为“MONKEY-1”的用户 - 如果用户想要发送请求,则必须使用“from,99,MONKEY-1”进行签名时尚。让我们假设它是这样的:

{ FROM: 99, TO: SERVER, COMMAND: GET-NEW-MAIL, SESSION: MONKEY-1 }

如果MONKEY-1是一个秘密,那就太好了。 (无论你喜欢什么格式,它都可能是4KiB二进制线噪声。)

然而,现在,我们有一个窃听者,他看到了这个数据包...她现在发送了自己的数据包。也许她很聪明,并且欺骗了真正的用户99正在使用的源IP地址 - 即使窃听者听不到您的回复,她仍然可以向您发送数据包。也许那个看起来像这样:

 { FROM: 99, TO: SERVER, COMMAND: DELETE-ALL-MAIL, SESSION: MONKEY-1 }

有许多方法可以防止这类事情的发生,其效果各不相同。在SSL中包装连接有助于使这非常困难(但绝不是不可能);这是很多网站都倒退的解决方案。更好的方法是使用双向通信以闯入者无法使用散列或公钥/私钥密码术获取秘密数据的方式对事物进行签名。例如,假设我们有这样的交换:

{ FROM: SERVER, TO: ??, COMMAND: PLEASE-LOGIN, NONCE: PIGEON }

{ FROM: BILL, TO: SERVER, COMMAND: LOGIN, AUTH: hash ( hash ( password ) . "PIGEON" ) }

...其中hash()表示SHA-256总和,而. "PIGEON"表示连接;

{ FROM: SERVER, TO: BILL, COMMAND: LOGIN-OK, SESSION: hash ( password ) ^ "MONKEY-1" }

...其中^指的是某些操作,如按位异或 - 或许。 然后,Bill随后发送这样的请求:

 { FROM: BILL, TO: SERVER, COMMAND: GET-NEW-MAIL, NONCE: "ARMADILLO", 
   AUTH: hash ( "GET-NEW-MAIL" . #\Newline . "ARMADILLO" . #\Newline . "MONKEY-1" ) }

现在,MONKEY-1在任何时候都没有明确的旅行;并且,每个请求上给出的AUTH密钥与使用的动词或命令以及随机数相关联,该随机数应根据每个请求而变化,并且服务器可以轻松验证其完整性,但窃听者不能再次重播相同的消息,或者更改动词并做一些不同的事情。

解释密码问题:

我有一个数据库表,它包含

User: BILL, Password: hash(DOLPHIN)

如果在电汇上,我会收到

{ FROM: BILL, PASSWORD: hash(DOLPHIN), COMMAND: GET-ALL-MAIL }

...那么窃听者不可能(但相当合理)知道密码是DOLPHIN,但是,她不需要知道或关心:

 { FROM: BILL, PASSWORD: hash(DOLPHIN), COMMAND: DELETE-ALL-MAIL }

你提到腌制密码......你会怎么做?

 User: BILL, PASSWORD: hash( SALT . DOLPHIN )

除非您单独存储SALT和DOLPHIN,否则您无法轻松获得 hash ( SALT . DOLPHIN )hash (DOLPHIN)。因此,用户必须向您提交hash ( SALT . DOLPHIN )(在客户端放置静态SALT),或者您必须再次存储明文密码。

解决方法可能是做

之类的事情
 Database: ( BILL => hash ( SALT . DOLPHIN ) )

 Server sends: ( NONCE )

 Client sends: ( BILL => hash ( NONCE . hash ( SALT . DOLPHIN ) ) )

答案 1 :(得分:4)

此类安全模型的一个重要方面是您存储密码的方式(或者更确切地说,您不存储密码的方式)。它并不像看起来那么简单,因为如果做得不正确会有很多危险。

This article涵盖了基础知识,并提供了一个很好的概述。它讨论了散列,彩虹表,盐析和慢速哈希函数。

由于您正在使用App Engine,因此您需要研究Python中的加密库。 hashlibhmac是标准库中的两个,但遗憾的是,Python的标准库没有任何慢速哈希函数的实现,如bcryptpbkdf2。< / p>

因此,我建议使用passlib进行密码哈希。我自己用它来做项目(正在进行的工作)。具体来说,我决定使用sha512_crypt - 您可以look at the code here(欢迎任何批评)。

显然,斯坦福大学还建造了JavaScript implementation的PBKDF2。