生成密码安全的身份validation令牌
背景:
这实际上是一个普遍的最佳实践问题,但是关于具体情况的一些背景可能会有帮助:
我们正在为iPhone开发一个“连接”应用程序。 它将通过REST服务与后端应用程序进行通信。 为了不必在每次启动应用程序时提示用户input用户名和密码,我们将公开一个“login”服务,在首次启动时validation用户名和密码,并返回一个可用于未来networking的身份validation令牌对真实数据的服务请求。 令牌可能会有一个到期时间,之后我们会要求他们用他们的用户名/密码重新进行validation。
问题:
生成这种用于身份validation的令牌的最佳做法是什么?
例如,我们可以…
- 散列(SHA-256等)一个随机string,并将其存储在给定用户的数据库中,并附带过期date。 在后续的请求上做一个简单的查询,以确保匹配。
- 使用密钥encryption用户标识和一些附加信息(时间戳等)。 解密后续请求令牌,以确保它是由我们发出的。
这感觉就像是一个解决的问题。
根据对这个问题的其他答案,额外的研究和离线讨论的反馈,这里是我们最终做的…
很快就指出,这里的交互模型与ASP.NET中的Forms Authentication使用的模型基本上完全相同,当选中“记住我”checkbox时。 这不仅仅是一个网页浏览器的HTTP请求。 我们的“票证”与表单身份validation所设置的cookie无异。 表单身份validation默认使用本质上是“使用密钥encryption某些数据”的方法。
在我们的loginWeb服务中,我们使用这个代码来创build一张票:
string[] userData = new string[4]; // fill the userData array with the information we need for subsequent requests userData[0] = ...; // data we need userData[1] = ...; // other data, etc // create a Forms Auth ticket with the username and the user data. FormsAuthenticationTicket formsTicket = new FormsAuthenticationTicket( 1, username, DateTime.Now, DateTime.Now.AddMinutes(DefaultTimeout), true, string.Join(UserDataDelimiter, userData) ); // encrypt the ticket string encryptedTicket = FormsAuthentication.Encrypt(formsTicket);
然后,我们有一个WCF服务的操作行为属性,添加一个IParameterInspector,检查请求的HTTP头中的有效票据。 开发人员将此操作行为属性放在需要身份validation的操作上。 以下是该代码parsing票证的方式:
// get the Forms Auth ticket object back from the encrypted Ticket FormsAuthenticationTicket formsTicket = FormsAuthentication.Decrypt(encryptedTicket); // split the user data back apart string[] userData = formsTicket.UserData.Split(new string[] { UserDataDelimiter }, StringSplitOptions.None); // verify that the username in the ticket matches the username that was sent with the request if (formsTicket.Name == expectedUsername) { // ticket is valid ... }
构build自己的authentication系统始终是“最糟糕的做法”。 对于专业authentication系统的专业人员来说,这是最好的一种方式。
如果你一心想build立自己的“从login服务到期的票”体系结构而不是重复使用现有的体系结构,那么至less应该熟悉推动类似系统devise的问题,比如Kerberos 。 这里有一个温柔的介绍:
http://web.mit.edu/kerberos/dialogue.html
在过去的20年中,查看Kerberos(以及类似系统)中发现的安全漏洞也是一个不错的主意,并确保您不会复制它们。 Kerberos由安全专家构build,经过数十年的仔细审查,仍然存在严重的algorithm漏洞,如下所示:
http://web.mit.edu/kerberos/www/advisories/MITKRB5-SA-2003-004-krb4.txt
从错误中学习比从自己的方面学习要好得多。
Amazon.com使用HMAC SHA-1消息令牌来validation和授权请求。 他们使用这个相当大的商业服务,所以我会负责相信他们的工程决定。 Google发布的OpenSocial API有些类似。 基于Google和Amazon.com使用类似和公开发布的方法来保护Web请求,我怀疑这可能是很好的方法。
你提供的两个答案中的任何一个都足够了。 你可能会在那里find为你做这个的框架,但事实是这并不难。 (我工作的每家公司都自己做了。)数据库存储的令牌与encryption的数据“cookies”的select是一个架构决定 – 是否要在每个页面视图上进行数据库查找,还是宁愿用cookie解密咀嚼CPU? 在大多数应用程序中,使用encryption的cookie可以提高性能(如果这是个问题)。 否则,这只是一个品味问题。
由于您使用的是WCF,因此如果使用CFNetwork,则有多种select – 例如NTLM或摘要式身份validation:
我知道这并不能回答你的具体问题,但我也遇到了这个问题(iPhone – Tomcat),并决定尽可能使用Web服务器上的authentication服务。 在大多数情况下,在每个请求中包含authentication信息并不会造成重大的惩罚。 一个快速的谷歌关于WCF和RESTful服务(和一些相关的问题在StackOverflow)上的博客文章。
希望这可以帮助!
你应该执行:
- OAuth2隐式授权 – 用于第三方应用程序http://tools.ietf.org/html/rfc6749#section-1.3.2
- OAuth2资源所有者密码凭证 – 用于您自己的移动应用程序http://tools.ietf.org/html/rfc6749#section-1.3.3
这正是您正在查找的来自OAuth2的工作stream程。 不要重新发明轮子。
这听起来像是一个具有很长的到期时间的会话标识符。 在Web应用程序中使用相同的原则可以在这里适用。
会话标识符是从非常大的空间(128位)随机select的,而不是编码信息。 服务器保持将会话标识符与用户相关联的logging以及诸如到期时间之类的其他期望的信息。 客户端通过每个请求的安全通道呈现会话标识符。
安全依赖于会话标识符的不可预测性。 从一个非常大的空间使用密码RNG生成它们。