REST API中基于令牌的身份验证

Pra*_*rat 3 security rest spring spring-security resteasy

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

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

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

  3. 对用户进行身份验证后,将从Redis数据库中的每个后续请求中检查令牌.

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

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

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

cas*_*lin 22

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

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

  1. 客户端将其凭据(用户名和密码)发送到服务器.
  2. 服务器验证凭据并生成令牌.
  3. 服务器将先前生成的令牌与用户标识符和到期日期一起存储在一些存储器中.
  4. 服务器将生成的令牌发送到客户端.
  5. 在每个请求中,客户端都将令牌发送到服务器.
  6. 每个请求中的服务器从传入请求中提取令牌.使用令牌,服务器查找用户详细信息以执行身份验证和授权.
    1. 如果令牌有效,则服务器接受该请求.
    2. 如果令牌无效,则服务器拒绝该请求.
  7. 服务器可以提供端点来刷新令牌.

如何将凭据发送到服务器

在REST应用程序中,从客户端到服务器的每个请求都必须包含服务器要理解的所有必要信息.有了它,您不依赖于存储在服务器上的任何会话上下文,也不会破坏Roy T. Fielding在其论文中定义的REST架构的无状态约束:

5.1.3无国籍

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

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

请查看RFC 7235中有关新身份验证方案注意事项的引用:

5.1.2.新身份验证方案的注意事项

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

  • HTTP认证被认为是无状态的:认证请求所需的所有信息必须在请求中提供,而不是依赖于服务器记住先前的请求.[...]

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

4.2.授权

的Authorization报头字段允许用户代理本身与源服务器进行认证-通常,但不一定,在接收到后401(未授权)响应.其值由包含所请求资源领域的用户代理的认证信息的凭证组成.

Authorization = credentials
Run Code Online (Sandbox Code Playgroud)

[...]

请注意,此HTTP标头的名称很不幸,因为它带有身份验证数据而不是授权.无论如何,这是发送凭据的标准标头.

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

什么令牌看起来像

认证令牌是由服务器生成的识别用户的一条数据.基本上,令牌可以是不透明的(除了值本身之外没有显示任何细节,如随机字符串)或者可以是自包含的(如JSON Web令牌):

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

  • JSON Web令牌(JWT):由RFC 7519定义,它是在两方之间安全地表示声明的标准方法.JWT是一个自包含的令牌,使您能够在有效负载中存储用户标识符,到期日期和任何您想要的(但不存储密码),这是一个编码为Base64的JSON.客户端可以读取有效负载,并且可以通过验证服务器上的签名来轻松检查令牌的完整性.如果您不需要跟踪JWT令牌,则无需持久保存JWT令牌.尽管如此,通过持久存在令牌,您将有可能使其无效并撤销其访问权限.要保持跟踪JWT令牌,而不是保留整个令牌,您可以保留令牌标识符(声明)和一些元数据(您发出令牌的用户,到期日期等),如果您需要.要找到一些与JWT合作的优秀资源,请查看http://jwt.io.jti

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

如何接受令牌

您永远不应接受未由您的申请签发的过期令牌或代币.如果您使用的是JWT,则必须检查令牌签名.

请注意,一旦您发出令牌并将其交给您的客户,您就无法控制客户端对令牌的处理方式.无法控制.认真.

通常的做法是检查User-Agent标题字段,以告知用于访问API的浏览器.但是,值得一提的是,HTTP标头很容易被欺骗,您永远不应该信任您的客户端.浏览器没有唯一标识符,但如果需要,您可以获得良好的指纹识别级别.

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

  • 检查用户在发出令牌时使用的浏览器.如果以下请求中的浏览器不同,则只需拒绝令牌.
  • 发出令牌时获取客户端远程地址(即客户端IP地址),并使用第三方API查找客户端位置.例如,如果以下请求来自其他国家/地区的地址,则拒绝令牌.要按IP地址查找位置,您可以尝试免费的API,如MaxMind GeoLite2或IPInfoDB.请注意,为API收到的每个请求命中第三方API并不是一个好主意,并且可能会对性能造成严重损害.但是,通过存储客户端远程地址及其位置,可以最大限度地减少对缓存的影响.现在有一些缓存引擎可用.仅举几例:番石榴,Infinispan,Ehcache和Spring.

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

顺便说一下,我提到过你永远不要相信你的客户吗?