RESTful 身份验证.客户端无状态未认证 [英] RESTful authentication. Client-side, stateless unauthentication

查看:28
本文介绍了RESTful 身份验证.客户端无状态未认证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为某些开发实现一组 RESTful 服务,其中一个是身份验证服务.

身份验证服务验证两种身份:

  • 应用程序.基于 AppKey 的身份验证,因此客户端必须注册密钥才能访问其余服务.
  • 用户.基于众所周知的凭据(用户+密码)的用户身份验证,因此人和机器可以通过客户端应用程序使用这些 RESTful 服务.

这些 RESTful 服务无状态.

当客户端应用程序针对身份验证服务进行身份验证时,或者当人或机器使用凭据作为身份进行身份验证时,这两种操作都会生成一个AppTokenUserToken 分别.

这些令牌是加盐哈希,因此对 RESTful 基础架构的后续请求将在不共享 AppKeys凭据 的情况下进行身份验证.

从完全无状态方法的角度来看,这些令牌不应存储在服务层的任何位置,而应存储在某种客户端状态(fe,Web 客户端将使用 HTTP cookie).这就是我目前的实现方式.

因为使用这些令牌重新验证每个请求,并让服务层接收来自客户端的令牌,以便它可以比较来自客户端的令牌检查它是否是一个有效的令牌,在服务层重新生成它并与客户端拥有的令牌进行比较太昂贵了,我已经实现了一个服务层AppTokenUserToken,两者都具有到期日期和所有者(为其创建令牌的应用程序或用户),以检查来自客户端的令牌是否存在于令牌存储中.>

客户端如何交互地取消身份验证? 只是删除客户端安全状态.如果是 Web 客户端,它会丢弃身份验证 cookie 并刷新页面,客户端未检测到身份验证 cookie,用户将被重定向到登录页面.

从 RESTful 服务的角度来看,这是一种无状态的未认证:客户端不知道具有服务层伪认证状态的技巧.这只是一个服务实现细节——一个性能优化——.

我不打算列出无状态服务的优点,因为我绝对确定这种方法是可行的,但我发现了一个问题:无状态身份验证/未身份验证意味着客户端不会通知服务器他们关闭他们的会话,因此安全存储以大量无用的记录结束.

如果服务客户端的会话时间有限(fe、1 小时、3 小时、一天……),这不是一个大问题,但是 如果用户必须经过身份验证会发生什么永远(8 个月,一年)?.你如何区分什么是过期令牌?

有一些方法可以解决这种情况:

  1. 每当服务层收到请求时,它都会更新令牌到期日期,因此自动化流程可能会丢弃那些已过期的令牌,定义令牌的任意到期时间(24 小时).

  2. 妥协架构的无状态性质,让客户端通知服务层他们不想再进行身份验证,因此服务可以将关联的令牌丢弃到客户端会话(但是等等...如果客户端关闭Web客户端会发生什么?用户永远不会主动通知服务必须丢弃令牌......所以......僵尸令牌已经存在,所以自动化过程应该丢弃它们,但是... 什么是僵尸令牌?我不喜欢这种方法).

  3. 完全无状态的身份验证,无需存储,按请求进行身份验证.

这就是问题!您建议的方法是什么 - 即使不是 1.、2. 或 3. - 为什么?

感谢您阅读这么长的文章——老实说,我相信这个问题的结论对任何人都非常有用——!

解决方案

选择的方法:COMPLETELY STATELESS AUTHENTICATION AND UNAUTHENTICATION

最后,我得到了一个结论和一个协议,以便切换到整个完全无状态的基于令牌的身份验证和非身份验证.

如何实现?

首先,这是为应用程序提供基于无状态令牌的身份验证所需要的(但用户身份验证的工作方式相同,不包括此清单):

  • 一个应用程序注册系统.应用程序是对您的服务的访问.它是您的应用程序访问网络(内联网、互联网、云...)上的某些服务.这是创建应用程序密钥(跳过此用于用户身份验证).
  • 使用 HTTPS/SSL 加密客户端到服务连接的服务器证书.

这是验证应用程序的流程:

  1. 客户端向身份验证服务发送身份验证请求.此请求必须包含应用程序密钥 (AppKey).

  2. 身份验证服务接收先前发送的请求.

  3. 现在身份验证服务创建一个应用程序令牌 (AppToken),它是必要信息的自描述串联,用于跟踪具体的经过身份验证的客户端到依赖身份验证服务的服务.

  4. AppToken 是一个复合字符串(这个组合可以是一个使用 JSON 序列化的对象):

    • 应用程序哈希(*a SHA - 或其他 - 这是连接一些应用程序信息的结果.这些信息将是服务机密 + 到期日期(这是令牌本身的一部分)).为什么要过期?.想象一下,一个中间人或其他东西可以破坏安全性并修改令牌的过期时间?当加密的令牌被解密以对请求进行身份验证时,再次散列过期的结果date + AppKey 将不再产生相同的哈希值,因此令牌将失效.
    • 发布日期.创建令牌时的当前 UTC 日期+时间.
    • 到期日期.令牌将不再有效的 UTC DateT+Time.
  5. 身份验证服务加密第 4 步的结果(JSON 序列化对象).**使用 AppKey 作为对称密码的密钥或密码.就我而言,我将使用 Rijndael.

  6. 后续请求将包含此令牌以避免发送纯文本凭据.这些请求也将始终包含 AppKey,因此身份验证服务将能够识别正在尝试对请求进行身份验证的应用程序.

  7. 一段时间后,令牌过期或无效,客户端请求新的 AppToken.或者客户端已被用户关闭,并且没有可以保存安全令牌的持久存储,因此下一个客户端会话将在需要时请求新的.

<小时>

有关此类身份验证方法的 .NET 实现的一些提示和细节:

  • 我使用 System.Security.Cryptography.RijndaelManaged 类进行对称加密.AppKey 和 AppToken(在基于令牌的用户身份验证的情况下,它几乎是相同的解决方案)都是使用 RijndaelManaged 类生成的.

  • 加密文本被转换为十六进制字符串.这与身份验证响应一起发送.在我们的例子中(一个 RESTFul API),表示 AppToken 的十六进制字符串将作为响应头发送.每当请求包含此 HEX 字符串时,身份验证过程都会将其重新转换为原始加密文本,然后对其进行解密以评估令牌是否有效.

<小时>

感谢 Henrik 的努力.我在你自己的答案中采用了一些概念,并将它们与我自己的结论混合在一起.

I'm implementing a set of RESTful services for some developments and one of these is an authentication service.

This authentication service authenticates two kinds of identities:

  • Applications. AppKey-based authentication so clients must register for a key in order to access to the rest of the services.
  • Users. Well-known credentials (user+password)-based user authentication so humans and machines can work with these RESTful services through client applications.

These RESTful services are stateless.

When a client application authenticates against the authentication service, or when a human or machine authenticates as an identity using credentials, both operations generates an AppToken and UserToken respectively.

These tokens are a salted hash so subsequent requests to the RESTful infrastructure will be authenticated without sharing AppKeys and credentials.

Form the point of view of a fully stateless approach, these tokens should be stored no where in the service layer but in some kind of client-side state (f.e., a Web client would store it using HTTP cookies). This is how my current implementations are working right now.

Because re-authenticating each request using these tokens and let the service layer receive the token coming from the client so it can compare what token comes from the client and check if it's a valid token re-generating it in the service layer and compare with the one owned by the client is too expensive, I've implemented a service layer AppToken and UserToken, both having an expiration date and an owner (the application or user for which the token have been created for), in order to check if the token coming from the client exists in the token store.

How does clients interactively unauthenticate? Just dropping client-side security state. If it's a Web client, it drops the authentication cookie and just refreshing the page, client detects no authentication cookie and user is redirected to the login page.

From the point of view of RESTful services, this is a stateless unauthentication: clients aren't aware about the trick of having a service layer pseudo-authentication state. It's just a service implementation detail - a performance optimization -.

I'm not going to list the pros of stateless services because I'm absolutely sure that this approach is the way to go, but I find a problem: stateless authentication/unauthentication means that clients don't notify server that they close their session, so the security store ends with a lot of useless records.

This isn't a great problem if service clients are ones that would have limited time sessions (f.e., 1 hour, 3 hours, a day...), but what happens if an user must be authenticated forever (8 months, a year)?. How do you distinguish what's an an expired token?

There're some approaches in order to solve this situation:

  1. Whenever the service layer receives a request, it updates token expiration date, so an automated process may drop those tokens that have expired defining an arbitrary expiration of tokens (f.e. 24 hours).

  2. Compromise stateless nature of the architecture and let clients notify service layer that they don't want to be authenticated anymore, so service can drop the associated token to the client session (But wait... what happens if client closes a Web client? User will never actively notify service that the token must be dropped... So... Zombie tokens are there yet, so an automated process should drop them, but... what's a zombie token? I don't like this approach).

  3. Completely stateless authentication, no store, per-request authentication.

This is the question! What's your suggested approach - even if it's not 1., 2. or 3. - and why?

Thanks for this long reading - I honestly believe that question's conclusions are going to be extremely useful to anyone -!

解决方案

Chosen approach: COMPLETELY STATELESS AUTHENTICATION AND UNAUTHENTICATION

Finally, I got a conclusion and a protocol in order to switch to the whole completely stateless token-based authentication and unauthentication.

How to achieve it?

First of all, this is what you need to have stateless token-based authentication for applications (but user authentication would work in the same way, excluding this inventory):

  • An application registration system. An application is an access to your services. It's "your application accessing some services on the net (intranet, internet, cloud...). This is creating application keys (skip this for user authentication).
  • A server certificate so client to service connections are encrypted by using HTTPS/SSL.

This is the flow of authenticating an application:

  1. Client sends an authentication request to the authentication service. This request must include the Application Key (AppKey).

  2. Authentication service receives the previously sent request.

  3. Now authentication service creates an application token (AppToken), which is a self-describing concatenation of the necessary information to track a concrete authenticated client to the services relying on authentication service.

  4. AppToken is a compound string (this composition can be an object serialized using JSON) of:

    • An application hash (*a SHA - or other - which is the result of concatenate some application info. This is info will be a service secret + Expiration date (which is part of the token itself). Why Expiration date?. Imagine that a man in the middle or something can break security and modify token's expiration? When encrypted token gets decrypted in order to authenticate a request, the result of hashing again the expiration date + AppKey will no longer produce the same hash, so token gets invalidated.
    • Issued date. Current UTC Date+Time when creating the token.
    • Expiration date. An UTC DateT+Time on which the token will be no longer valid.
  5. Authentication service encrypts step #4 result (the JSON-serialized object). **Use AppKey as the key or password for a symmetric cipher. In my case, I'll use Rijndael for that.

  6. Subsequent request will include this token in order to avoid sending plain text credentials. Those request will always include the AppKey too, so authentication service will be able of identify what application is trying to authenticate the request.

  7. After some time, a token becomes expired or invalid, and client requests for a new AppToken. Or the client was closed by the user and there's no persistent storage that would save security tokens, so next client session will request new ones when needed.


Some hints and details about .NET implementation of such authentication method:

  • I've used System.Security.Cryptography.RijndaelManaged class for symmetric encryption. Both AppKey and AppToken (and in case of token-based user authentication it's almost the same solution) are generated using RijndaelManaged class.

  • Encrypted text is converted to an HEX string. This is sent with the authentication response. In our case (a RESTFul API), the HEX string representing the AppToken will be sent as a response header. Whenever a request includes this HEX string, authentication process will reconvert it to the original encrypted text, and later it'll get decrypted in order to evaluate if the token is valid.


Thanks Henrik for your effort. I've taken some of concepts in your own answer and I've mixed them with my own conclusions.

这篇关于RESTful 身份验证.客户端无状态未认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆