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

C# 生成加密安全的身份验证令牌,c#,iphone,wcf,web-services,security,C#,Iphone,Wcf,Web Services,Security,背景: 这确实是一个一般性的最佳实践问题,但有关具体情况的一些背景可能会有所帮助: 我们正在为iPhone开发一个“联网”应用程序。它将通过REST服务与后端应用程序通信。为了不必在用户每次启动应用程序时都提示用户输入用户名和密码,我们将公开一个“登录”服务,该服务在初始启动时验证用户的用户名和密码,并返回一个身份验证令牌,该令牌可用于将来对真实数据的web服务请求。令牌可能有一个过期时间,在此之后,我们将要求他们使用用户名/密码重新验证 问题: 生成用于身份验证的此类令牌的最佳实践是什么 例如

背景:

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

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

问题:

生成用于身份验证的此类令牌的最佳实践是什么

例如,我们可以

  • 散列(SHA-256等)一个随机字符串,并将其与过期日期一起存储在给定用户的数据库中。对后续请求中的令牌执行简单的查找,以确保其匹配
  • 使用密钥加密用户id和一些附加信息(时间戳等)。在后续请求中解密令牌,以确保它是由我们发布的

这似乎是一个必须解决的问题。

这听起来就像是一个过期时间很长的会话标识符。在web应用程序中使用的相同原则也适用于此

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


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

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

如果您决心构建自己的“登录服务过期票据”体系结构,而不是重复使用现有的体系结构,那么至少应该熟悉驱动类似系统(如Kerberos)设计的问题。这里有一个温和的介绍:

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


从他们的错误中吸取教训比从自己的错误中吸取教训要好得多。

Amazon.com使用身份验证和授权请求。他们将此用于相当大的商业服务,因此我会相信他们的工程决策。谷歌发布了与之有几分相似的信息。基于Google和Amazon.com使用类似的公开发布的方法来保护web请求的安全,我怀疑这些方法可能是很好的方法。

因为您使用的是WCF,如果使用CFNetwork,您有多种选择——例如NTLM或摘要身份验证:

我知道这并没有回答您的具体问题,但我也遇到了这个问题(iPhone-Tomcat),并决定尽可能多地使用web服务器上的身份验证服务。在大多数情况下,在每个请求中包含身份验证信息不会带来重大损失。一个快速的Google会发现很多关于WCF和RESTful服务的博客帖子(以及一些关于StackOverflow的相关问题)


希望这有帮助

您提供的两个答案中的任何一个都足够了。您可能会发现有一些框架可以为您做到这一点,但事实上,构建起来并不难。(我工作过的每家公司都推出了自己的产品。)选择数据库存储令牌还是加密数据“cookie”是一个体系结构决策——您是希望在每个页面视图上进行数据库查找,还是宁愿用cookie解密来消耗CPU?在大多数应用程序中,使用加密cookie可以在一定程度上提高性能(如果这是一个问题的话)。否则,这只是品味的问题。

根据对这个问题的其他答案、额外研究和离线讨论的反馈,以下是我们最终要做的

有人很快指出,这里的交互模型本质上与ASP.NET中窗体身份验证在选中“记住我”复选框时使用的模型完全相同。它不是一个web浏览器发出HTTP请求。我们的“票据”相当于形成身份验证集的cookie。默认情况下,表单身份验证基本上使用“使用密钥加密某些数据”的方法

在我们的登录web服务中,我们使用以下代码创建票证:

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服务添加了一个操作行为属性,该属性添加了一个IPParameterInspector,用于检查请求的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
    ...
}
你应该实施:

  • OAuth2隐式授权-用于第三方应用程序
  • OAuth2资源所有者密码凭据-用于您自己的移动应用程序

  • 这正是您正在寻找的OAuth2中的工作流。不要重新发明轮子。

    如果iPhone应用程序和REST WCF web服务之间有一个现成的身份验证系统,请发布一个链接,我很乐意使用它,而不是发明我们自己的。。。在此,我当然会看一看您提供的kerberos链接。请直接使用RESTful API登录时的最佳实践