生成加密安全身份验证令牌

时间:2009-05-08 15:57:58

标签: c# iphone wcf web-services security

背景

这实际上是一个一般的最佳实践问题,但有关具体情况的一些背景可能会有所帮助:

我们正在为iPhone开发一个“连接”应用程序。它将通过REST服务与后端应用程序通信。为了在每次启动应用程序时不必提示用户输入用户名和密码,我们将公开一个“登录”服务,该服务在初始启动时验证其用户名和密码,并返回可用于将来Web的身份验证令牌服务请求真实数据。令牌可能有一个到期时间,之后我们会要求他们使用他们的用户名/密码重新进行身份验证。

问题:

生成此类令牌以用于身份验证的最佳做法是什么?

例如,我们可以......

  • 哈希(SHA-256等)随机字符串,并将其存储在给定用户的数据库中,并将其存档到期日期。在后续请求中对令牌进行简单查找,以确保它匹配。
  • 使用密钥加密用户ID和一些其他信息(时间戳等)。在后续请求中解密令牌,以确保它是由我们发出的。

这感觉它必定是一个已解决的问题。

7 个答案:

答案 0 :(得分:29)

根据这个问题的其他答案的反馈,进一步的研究和离线讨论,这是我们最终做的...

很快就指出,当选中“记住我”复选框时,此处的交互模型与ASP.NET中的表单身份验证使用的模型基本完全相同。它不是发出HTTP请求的Web浏览器。我们的“票证”与表单身份验证设置的cookie等效。表单身份验证默认使用“加密一些带密钥的数据”方法。

在我们的登录网络服务中,我们使用此代码创建故障单:

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头中的有效票证。开发人员将此操作行为属性放在需要身份验证的操作上。以下是该代码解析故障单的方式:

// 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
    ...
}

答案 1 :(得分:13)

构建自己的身份验证系统始终是“最糟糕的做法”。这是专门从事认证系统的专业人士最好的事情。

如果您倾向于从登录服务构建自己的“过期票证”架构而不是重新使用现有架构,那么至少熟悉驱动类似系统设计的问题可能是个好主意。 ,像Kerberos。这里有一个温和的介绍:

http://web.mit.edu/kerberos/dialogue.html

在过去20年中,了解Kerberos(和类似系统)中发现的安全漏洞并确保不复制它们也是一个好主意。 Kerberos由安全专家构建并经过数十年的仔细审查,并且仍然存在严重的算法缺陷,如下所示:

http://web.mit.edu/kerberos/www/advisories/MITKRB5-SA-2003-004-krb4.txt

从他们的错误中学习比你自己的错误要好得多。

答案 2 :(得分:11)

Amazon.com使用HMAC SHA-1 message token对请求进行身份验证和授权。他们将此用于相当大的商业服务,因此我有责任相信他们的工程决策。谷歌发布的OpenSocial API有点类似。基于Google和Amazon.com使用类似且公开发布的方法来保护Web请求,我怀疑这些可能是很好的方法。

答案 3 :(得分:3)

您提供的两个答案中的任何一个都足够了。你可能会找到那些为你做这个的框架,但事实是它并不难建立。 (我所工作过的每一家公司都已经推出了自己的公司。)数据库存储令牌与加密数据“cookies”的选择是一个架构决策 - 你想在每个页面视图上进行数据库查找,还是你愿意?用cookie解密来咀嚼CPU?在大多数应用程序中,使用加密的cookie可以大规模地提升性能(如果这是一个问题)。否则,这只是一个品味问题。

答案 4 :(得分:1)

由于您正在使用WCF,因此如果使用CFNetwork,您可以使用各种选项 - 例如NTLM或摘要式身份验证:

http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/Concepts/Concepts.html#//apple_ref/doc/uid/TP30001132-CH4-SW7

我知道这不能解答您的具体问题,但我也遇到过这个问题(iPhone - Tomcat),并决定尽可能使用Web服务器上的身份验证服务。在大多数情况下,对每个请求包含身份验证信息没有明显的损失。一个快速的谷歌出现了很多关于WCF和RESTful服务的博客文章(以及关于StackOverflow的一些相关问题)。

希望这有帮助!

答案 5 :(得分:1)

你应该实现:

  1. OAuth2隐式授权 - 适用于第三方应用http://tools.ietf.org/html/rfc6749#section-1.3.2
  2. OAuth2资源所有者密码凭据 - 适用于您自己的移动应用http://tools.ietf.org/html/rfc6749#section-1.3.3
  3. 正是您正在寻找的来自OAuth2的工作流程。不要重新发明轮子。

答案 6 :(得分:0)

这听起来像是具有较长过期时间的会话标识符。 Web应用程序中使用的相同原则可以在此处应用。

不是编码信息,而是从非常大的空间(128位)中随机选择会话标识符。服务器保存将会话标识符与用户相关联的记录以及诸如到期时间之类的其他所需信息。客户端在每个请求的安全通道上显示会话标识符。

安全性依赖于会话标识符的不可预测性。使用加密RNG从非常大的空间生成它们。