C# 生成加密安全的身份验证令牌
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/840537/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generating cryptographically secure authentication tokens
提问by Erv Walter
Background:
背景:
This is really a general best-practices question, but some background about the specific situation might be helpful:
这确实是一个通用的最佳实践问题,但有关特定情况的一些背景可能会有所帮助:
We are developing a "connected" application for the iPhone. It will communicate with the backend application via REST services. In order to not have to prompt the user for a username and password every time they launch the application, we will expose a "Login" service that validates their username and password on initial launch and returns an authentication token that can be used for future web service requests for real data. The token may have an expiration time after which we'll ask them to re-authenticate with their username/password.
我们正在为 iPhone 开发一个“连接”的应用程序。它将通过 REST 服务与后端应用程序通信。为了不必每次启动应用程序时都提示用户输入用户名和密码,我们将公开一个“登录”服务,该服务在初始启动时验证他们的用户名和密码,并返回可用于未来网络的身份验证令牌真实数据的服务请求。令牌可能有一个过期时间,在此之后我们会要求他们使用他们的用户名/密码重新进行身份验证。
The Question:
问题:
What are the best practices for generating this sort of token to be used for authentication?
生成这种用于身份验证的令牌的最佳实践是什么?
For example, we could...
例如,我们可以...
- Hash (SHA-256, etc) a random string and store it in the database for the given user along with an expiration date. Do a simple lookup of the token on subsequent requests to make sure it matches.
- Encrypte the user id and some additional information (timestamp, etc) with a secret key. Decrypt the token on subsequent requests to make sure it was issued by us.
- 散列(SHA-256 等)随机字符串并将其存储在给定用户的数据库中以及到期日期。在后续请求中对令牌进行简单的查找以确保它匹配。
- 使用密钥加密用户 ID 和一些附加信息(时间戳等)。在后续请求中解密令牌以确保它是由我们发出的。
This feels like it must be a solved problem.
这感觉就像它必须是一个已解决的问题。
采纳答案by Erv Walter
Based on the feedback from the other answers to this question, additional research, and offline discussions, here is what we ended up doing...
根据对这个问题的其他答案、额外的研究和离线讨论的反馈,这是我们最终做的……
It was pointed out pretty quickly that the interaction model here is essentially exactly the same as the model used by Forms Authentication in ASP.NET when a "remember me" checkbox is checked. It's just not a web browser making the HTTP requests. Our "ticket" is equivilant to the cookie that Forms Authentication sets. Forms Authentication uses essentially an "encrypt some data with a secret key" approach by default.
它被指出很快,即在这里将其交互模型与ASP.NET中的表单身份验证使用的模型完全完全相同。选中“记住我”复选框。它不是发出 HTTP 请求的 Web 浏览器。我们的“票”等同于 Forms Authentication 设置的 cookie。默认情况下,表单身份验证本质上使用“使用密钥加密某些数据”方法。
In our login web service, we use this code to create a ticket:
在我们的登录 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);
Then we have an operation behavior attribute for the WCF services that adds an IParameterInspector that checks for a valid ticket in the HTTP headers for the request. Developers put this operation behavior attribute on operations that require authentication. Here is how that code parses the ticket:
然后我们有一个 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
...
}
回答by erickson
This simply sounds like a session identifier with a long expiration time. The same principles used for this in web applications could apply here.
这听起来像是一个过期时间很长的会话标识符。在 Web 应用程序中用于此的相同原则可以在这里应用。
Rather than encoding information, session identifiers are randomly chosen from a very large space (128 bits). The server keeps a record associating the session identifier with the user and other desired information such as expiration time. The client presents the session identifier over a secure channel with each request.
会话标识符不是编码信息,而是从非常大的空间(128 位)中随机选择。服务器保留将会话标识符与用户和其他所需信息(例如到期时间)相关联的记录。客户端通过安全通道为每个请求提供会话标识符。
Security relies on the unpredictability of the session identifiers. Generate them with a cryptographic RNG, from a very large space.
安全性依赖于会话标识符的不可预测性。使用加密 RNG 从非常大的空间生成它们。
回答by Eric Lippert
Building your own authentication system is always a "worst practice". That's the kind of thing best left to professionals who specialize in authentication systems.
构建自己的身份验证系统始终是“最糟糕的做法”。这种事情最好留给专门从事身份验证系统的专业人士处理。
If you're bent on building your own "expiring ticket from a login service" architecture rather than re-using an existing one, it's probably a good idea to at least familiarize yourself with the issues that drove the design of similar systems, like Kerberos. A gentle introduction is here:
如果您一心想要构建自己的“登录服务过期票证”架构,而不是重新使用现有架构,那么至少熟悉驱动类似系统设计的问题可能是个好主意,例如 Kerberos . 一个温和的介绍在这里:
http://web.mit.edu/kerberos/dialogue.html
http://web.mit.edu/kerberos/dialogue.html
It would also be a good idea to take a look at what security holes have been found in Kerberos (and similar systems) over the last 20 years and make sure you don't replicate them. Kerberos was built by security experts and carefully reviewed for decades, and still serious algorithmic flaws are being found in it, like this one:
查看过去 20 年来在 Kerberos(和类似系统)中发现的安全漏洞并确保您没有复制它们也是一个好主意。Kerberos 由安全专家构建并经过数十年的仔细,仍然发现其中存在严重的算法缺陷,例如:
http://web.mit.edu/kerberos/www/advisories/MITKRB5-SA-2003-004-krb4.txt
http://web.mit.edu/kerberos/www/advisories/MITKRB5-SA-2003-004-krb4.txt
It's a lot better to learn from their mistakes than your own.
从他们的错误中吸取教训比从自己的错误中吸取教训要好得多。
回答by Alex Reynolds
Amazon.com uses a HMAC SHA-1 message tokento authenticate and authorize requests. They use this for a fairly large commercial service, so I'd be liable to trust their engineering decisions. Google publishes the OpenSocial APIwhich is somewhat similar. Based on Google and Amazon.com using similar and openly published approaches to securing web requests, I suspect these are probably good ways to go.
Amazon.com 使用HMAC SHA-1 消息令牌来验证和授权请求。他们将其用于相当大的商业服务,因此我可以相信他们的工程决策。谷歌发布的OpenSocial API有点类似。基于 Google 和 Amazon.com 使用类似且公开发布的方法来保护 Web 请求,我怀疑这些可能是不错的方法。
回答by sehugg
Since you're using WCF, you have a variety of options if using CFNetwork -- for instance NTLM or Digest Authentication:
由于您使用的是 WCF,如果使用 CFNetwork,您有多种选择——例如 NTLM 或摘要式身份验证:
I know this doesn't answer your specific question, but I have also been faced with this problem (iPhone - Tomcat) and decided to use the authentication services on the web server as much as possible. There's no significant penalty for including the authentication information with each request in most cases. A quick Google turns up lots of blog posts about WCF and RESTful services (and some related questions on StackOverflow).
我知道这不能回答您的具体问题,但我也遇到过这个问题(iPhone - Tomcat)并决定尽可能多地使用 Web 服务器上的身份验证服务。在大多数情况下,将身份验证信息包含在每个请求中不会造成重大损失。一个快速的谷歌出现了很多关于 WCF 和 RESTful 服务的博客文章(以及一些关于 StackOverflow 的相关问题)。
Hope this helps!
希望这可以帮助!
回答by Neil Mix
Either of the two answers you've provided will suffice. You may find frameworks out there that do this for you, but the truth is it's not that hard to build. (Every company I've worked for has rolled their own.) The choice of database-stored tokens versus encrypted data "cookies" is an architectural decision -- do you want to incur a database lookup on every page view, or would you rather chew up CPU with cookie decryption? In most applications, using encrypted cookies provides a performance win at scale (if that's a concern). Otherwise it's just a matter of taste.
您提供的两个答案中的任何一个就足够了。您可能会找到为您执行此操作的框架,但事实是构建起来并不难。(我工作过的每家公司都推出了自己的公司。)数据库存储令牌与加密数据“cookies”的选择是一个架构决策——你想在每次页面查看时都进行数据库查找,还是更愿意?用cookie解密咀嚼CPU?在大多数应用程序中,使用加密的 cookie 可提供大规模的性能优势(如果这是一个问题)。否则,这只是品味问题。
回答by irakli
You should implement:
你应该实施:
- OAuth2 Implicit Grant - for third-party applications http://tools.ietf.org/html/rfc6749#section-1.3.2
- OAuth2 Resource Owner Password Credentials — for your own mobile application http://tools.ietf.org/html/rfc6749#section-1.3.3
- OAuth2 隐式授权 - 适用于第三方应用程序http://tools.ietf.org/html/rfc6749#section-1.3.2
- OAuth2 资源所有者密码凭证 — 用于您自己的移动应用程序http://tools.ietf.org/html/rfc6749#section-1.3.3
which are exactly the workflows, from OAuth2, that you are looking for. Do not reinvent the wheel.
这正是您正在寻找的来自 OAuth2 的工作流。不要重新发明轮子。