REST API中基于令牌的身份验证 [英] Token based authentication in REST APIs

查看:167
本文介绍了REST API中基于令牌的身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图实现基于令牌的身份验证方法:

I trying to implement a token based authentication approach:

  1. 每次成功登录都会创建新令牌.

  1. Every successful login creates new token.

如果用户选择保持登录状态"或用户正在使用移动设备,则令牌将保留在Redis数据库中,而不会过期.否则,令牌将在20分钟后失效.

If user selects "keep me logged in" or the user is using a mobile device, the token is persisted in a Redis database without an expiration date. Otherwise, the token will expire in 20 minutes.

用户通过身份验证后,将从我的Redis数据库中的每个后续请求中检查令牌.

Once user is authenticated, the token is checked from each subsequent request in my Redis database.

我想知道如何识别设备.对于移动设备,我可以使用设备标识符.但是如何识别浏览器?

I'm wondering how I can identify devices. In case of mobile devices, I can use a device identifier. But how can I identify a browser?

示例:用户使用Chrome登录,然后选择保持登录状态".会生成一个令牌,并将其与浏览器名称一起保存在Redis中.如果用户从Firefox登录,则将令牌和"Firefox"保存在数据库中.我将令牌保存在Redis中,而令牌是在成功身份验证后创建的.仅保留令牌和使用令牌的浏览器是否可以持久?还是我也需要保留IP?

Example: The user logs in using Chrome and selects "keep me logged in". A token is generated and persisted with the browser name in Redis. If the user logs in from Firefox, saves the token and "Firefox" in the database. I save the token in Redis whereas token is created on successful authentication. Is it fine to persist only the token and the browser where the token is being used? Or do I need to persist the IP as well?

其他问题:如何避免攻击者从cookie中窃取令牌?

Additional question: How to avoid attackers to steal the token from a cookie?

推荐答案

基于令牌的身份验证的工作原理

简而言之,基于令牌的身份验证方案遵循以下步骤:

How token-based authentication works

In a few words, an authentication scheme based on tokens follow these steps:

  1. 客户端将其凭据(用户名和密码)发送到服务器.
  2. 服务器对凭据进行身份验证并生成令牌.
  3. 服务器将先前生成的令牌以及用户标识符和到期日期存储在某个存储器中.
  4. 服务器将生成的令牌发送给客户端.
  5. 在每个请求中,客户端都会将令牌发送到服务器.
  6. 服务器在每个请求中均从传入请求中提取令牌.服务器使用令牌来查找用户详细信息以执行身份验证和授权.
  1. The client sends their credentials (username and password) to the server.
  2. The server authenticates the credentials and generates a token.
  3. The server stores the previously generated token in some storage along with the user identifier and an expiration date.
  4. The server sends the generated token to the client.
  5. In every request, the client sends the token to the server.
  6. The server, in each request, extracts the token from the incoming request. With the token, the server looks up the user details to perform authentication and authorization.
  1. 如果令牌有效,则服务器接受请求.
  2. 如果令牌无效,则服务器拒绝该请求.

  • 服务器可以提供端点以刷新令牌.
  • 如何将凭据发送到服务器

    在REST应用程序中,从客户端到服务器的每个请求必须包含服务器必须理解的所有必要信息.使用它,您将不依赖于存储在服务器上的任何会话上下文,并且不会破坏

    > 5.1.3无状态

    [...]从客户端到服务器的每个请求必须包含理解该请求所需的所有信息,并且不能利用服务器上任何已存储的上下文.因此,会话状态完全保留在客户端上. [...]

    [...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]

    访问需要身份验证的受保护资源时,每个请求必须包含所有需要正确身份验证/授权的数据.这意味着将对每个请求执行身份验证.

    When accessing protected resources that require authentication, each request must contain all necessary data to be properly authenticated/authorized. It means the authentication will be performed for each request.

    请参见 RFC 7235 中的引号对于新的身份验证方案:

    Have a look at this quote from the RFC 7235 regarding considerations for new authentication schemes:

    5.1.2.新认证方案的注意事项

    HTTP身份验证框架的某些方面 限制了新的身份验证方案的工作方式:

    There are certain aspects of the HTTP Authentication Framework that put constraints on how new authentication schemes can work:

    • 假定HTTP身份验证是无状态的:所有 必须提供验证请求所需的信息 在请求中,而不是依赖于服务器的记忆 事先要求. [...]
    • HTTP authentication is presumed to be stateless: all of the information necessary to authenticate a request MUST be provided in the request, rather than be dependent on the server remembering prior requests. [...]

    并且身份验证数据(凭据)应属于标准HTTP Authorization 标头.来自 RFC 7235 :

    And authentication data (credentials) should belong to the standard HTTP Authorization header. From the RFC 7235:

    4.2.授权

    Authorization标头字段允许用户代理进行身份验证 本身与原始服务器一起使用-通常(但不一定)在 收到401(未经授权)响应.其值包括 包含用户身份验证信息的凭据 所请求资源领域的代理.

    The Authorization header field allows a user agent to authenticate itself with an origin server -- usually, but not necessarily, after receiving a 401 (Unauthorized) response. Its value consists of credentials containing the authentication information of the user agent for the realm of the resource being requested.

    Authorization = credentials
    

    [...]

    请注意,此HTTP标头的名称很不幸,因为它包含 authentication 数据而不是 authorization .无论如何,这是用于发送凭据的标准标头.

    Please note that the name of this HTTP header is unfortunate because it carries authentication data instead of authorization. Anyways, this is the standard header for sending credentials.

    执行基于令牌的身份验证时,令牌是您的凭据.通过这种方法,您的硬凭证(用户名和密码)将交换为在每个请求中发送的令牌.

    When performing a token based authentication, tokens are your credentials. In this approach, your hard credentials (username and password) are exchanged for a token that is sent in each request.

    身份验证令牌是服务器生成的用于标识用户的一条数据.基本上,令牌可以是不透明(除了值本身,它不显示任何细节,例如随机字符串),也可以是自包含(例如 JSON Web令牌):

    An authentication token is a piece of data generated by the server which identifies a user. Basically, tokens can be opaque (which reveals no details other than the value itself, like a random string) or can be self-contained (like JSON Web Token):

    • 随机字符串:可以通过生成随机字符串并将其具有到期日期和与之关联的用户标识符持久存储到数据库中来发行令牌.

    • Random string: A token can be issued by generating a random string and persisting it to a database with an expiration date and with a user identifier associated to it.

    JSON Web令牌(JWT):由 RFC 7519定义,这是一种在两方之间安全地表示索赔的标准方法. JWT是一个自包含的令牌,可让您在有效负载中存储用户标识符,有效期以及您想要的任何内容(但不存储密码),该内容为 http://jwt.io .

    JSON Web Token (JWT): Defined by the RFC 7519, it's a standard method for representing claims securely between two parties. JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64. The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server. You won't need to persist JWT tokens if you don't need to track them. Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To keep the track of JWT tokens, instead of persisting the whole token, you could persist the token identifier (the jti claim) and some metadata (the user you issued the token for, the expiration date, etc) if you need. To find some great resources to work with JWT, have a look at http://jwt.io.

    提示:始终考虑删除旧令牌,以防止数据库无限期增长.

    Tip: Always consider removing old tokens in order to prevent your database from growing indefinitely.

    您应该从不接受过期的令牌或应用程序未发行的令牌.如果您使用的是JWT,则必须检查令牌签名.

    You should never accept expired tokens or tokens which were not issued by your application. If you are using JWT, you must check the token signature.

    请注意,一旦您发行了令牌并将其提供给客户,您将无法控制客户对令牌的处理方式. 没有控制权. 认真.

    Please note, once you issue a token and give it to your client, you have no control over what the client will do with the token. No control. Seriously.

    通常的做法是检查 User-Agent 标头字段告诉正在使用哪个浏览器访问您的API.但是,值得一提的是,HTTP标头可以被容易地被欺骗,您应该永远不要信任您的客户端.浏览器没有唯一的标识符,但是您可以根据需要获得指纹的高级级别.

    It's a common practice to check the User-Agent header field to tell which browser is being used to access your API. However, it's worth mention that HTTP headers can be easily spoofed and you should never trust your client. Browsers don't have unique identifier, but you can get a good level of fingerprinting if you want.

    我不知道您的安全要求,但是您始终可以在服务器中尝试以下操作以增强API的安全性:

    I don't know about your security requirements, but you always can try the following in your server to enhance the security of your API:

    • 检查颁发令牌时用户使用的浏览器.如果以下请求中的浏览器不同,则拒绝令牌.
    • 获取颁发令牌时的客户端远程地址(即客户端IP地址),并使用第三方API查找客户端位置.例如,如果以下请求来自其他国家/地区的地址,请拒绝该令牌.要按IP地址查找位置,可以尝试使用免费的API,例如 MaxMind GeoLite2 IPInfoDB .请注意,对于您的API收到的每个请求都命中第三方API并不是一个好主意,并且可能会对性能造成严重损害.但是,通过存储客户端远程地址及其位置,可以使用 cache 将影响降到最低.如今有一些缓存引擎可用.仅举几例:番石榴 Ehcache
    • Check which browser the user was using when the token was issued. If the browser is different in the following requests, just refuse the token.
    • Get the client remote address (that is, the client IP address) when the token was issued and use a third party API to lookup the client location. If the following requests comes an address from other country, for example, refuse the token. To lookup the location by IP address, you can try free APIs such as MaxMind GeoLite2 or IPInfoDB. Mind that hitting a third party API for each request your API receives is not a good idea and can cause a severe damage to the performance. But you can minimize the impact with a cache, by storing the client remote address and its location. There are a few cache engines available nowadays. To mention a few: Guava, Infinispan, Ehcache and Spring.

    通过网络发送敏感数据时,最好的朋友是HTTPS,它可以保护您的应用程序免受中间人攻击.

    When sending sensitive data over the wire, your best friend is HTTPS and it protects your application against the man-in-the-middle attack.

    顺便说一句,我是否提到过您不应该信任您的客户?

    By the way, have I mentioned you should never trust your client?

    这篇关于REST API中基于令牌的身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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