REST API:简单的基于令牌的身份验证 - 安全性?
REST API: Simple token-based authentication - security?
我有一个 REST API,我正在寻找一种简单的方法来进行基于令牌的安全身份验证。因为我读到像 OAuth 这样的协议非常复杂,所以我想实现一种更简单的方法。常见的方法有哪些?那么下面程序的安全性如何?
- 客户端输入电子邮件和密码 -> 将其发送到 REST API(通过 HTTPS)
- API验证用户
- 如果登录数据正确,API 会生成一个唯一的 API 令牌,将其保存在数据库中供用户使用,然后将其发送回客户端
- 令牌存储在客户端网络存储
- 对于以下请求,客户端每次都必须发送token并且API每次都必须检查token
- 注销时,token从webstorage和数据库中删除(用户再次登录时生成新的token)
这种方法是否存在严重的安全问题?还是可行?
非常感谢
简短的回答是这种方法的概念没有重大安全问题,但实施是关键,这可能是我最重要的一点。
自定义实现问题
你描述的基本上是一个普通的旧session。这里的 "token" 只是一个 session id。 Web 应用程序多年来一直以这种方式工作。已知的高质量实现可以避免 session 固定、弱或不安全的 session id 生成等,还有一长串 session 管理漏洞。如果您尝试自己实施它,那么要使其正确和安全并不容易。因此,如果您打算这样做,只需使用已知的良好实现即可。
XSS 问题
不过有一点不同,你想将你的 "token" (session id) 存储在 "webstorage" 中,它可以是 localStorage、sessionStorage 或WebSQL 基本上。传统的 session 管理将 session id 存储在 cookie 中是有充分理由的——可以更好地保护 cookie 免受 cross-site 脚本(XSS)攻击。如果 session cookie 被标记为 httpOnly,Javascript 将无法访问它,它只会被浏览器发送回同一服务器(实际上是源)。这对于任何其他存储都是不可能的,这意味着如果您的站点(同一来源的任何页面)中存在 XSS 漏洞,则用户令牌可能会被盗。这明显不如使用 httpOnly cookie 安全。
在现代 Web 应用程序中,这是一个可以接受的风险很多次。这主要发生在您想要将相同的令牌发送到多个服务器(源)时。使用 httpOnly cookie 是不可能的。但是,如果您的令牌存储在数据库中,那么出于架构原因,您可能不想这样做。
CSRF 问题 - 已阻止
另请注意,尽管这种设计在 headers 中发送令牌几乎默认情况下可防止 cross-site 请求伪造 (CSRF)。所以好处是你不必(太多)关心 CSRF,但这是以 XSS 影响为代价的,并且在大多数情况下超过了这个好处。
状态问题
最后一点,这不是安全问题,但使用您的设计,您的 API 将是有状态的,它将为每个客户端存储一个状态。这不是很好,因为正如您所说的那样,您将不得不去数据库检查每个请求的令牌(或者您可以深入缓存和类似的复杂性来源)。然后想象一下,如果您的服务需要在多个服务器上 load-balanced、运行 并具有多个数据库副本实例,会发生什么情况。因此,现代 API 设计的目标是无状态——不为客户端存储状态。这就是(真正的)令牌认证的亮点,令牌不需要存储到数据库中,它们本身就是真实的。这就是 token-based 身份验证真正有意义的地方,而不是在简单的情况下,普通的 session id 也可以,并且会更安全。
我有一个 REST API,我正在寻找一种简单的方法来进行基于令牌的安全身份验证。因为我读到像 OAuth 这样的协议非常复杂,所以我想实现一种更简单的方法。常见的方法有哪些?那么下面程序的安全性如何?
- 客户端输入电子邮件和密码 -> 将其发送到 REST API(通过 HTTPS)
- API验证用户
- 如果登录数据正确,API 会生成一个唯一的 API 令牌,将其保存在数据库中供用户使用,然后将其发送回客户端
- 令牌存储在客户端网络存储
- 对于以下请求,客户端每次都必须发送token并且API每次都必须检查token
- 注销时,token从webstorage和数据库中删除(用户再次登录时生成新的token)
这种方法是否存在严重的安全问题?还是可行?
非常感谢
简短的回答是这种方法的概念没有重大安全问题,但实施是关键,这可能是我最重要的一点。
自定义实现问题
你描述的基本上是一个普通的旧session。这里的 "token" 只是一个 session id。 Web 应用程序多年来一直以这种方式工作。已知的高质量实现可以避免 session 固定、弱或不安全的 session id 生成等,还有一长串 session 管理漏洞。如果您尝试自己实施它,那么要使其正确和安全并不容易。因此,如果您打算这样做,只需使用已知的良好实现即可。
XSS 问题
不过有一点不同,你想将你的 "token" (session id) 存储在 "webstorage" 中,它可以是 localStorage、sessionStorage 或WebSQL 基本上。传统的 session 管理将 session id 存储在 cookie 中是有充分理由的——可以更好地保护 cookie 免受 cross-site 脚本(XSS)攻击。如果 session cookie 被标记为 httpOnly,Javascript 将无法访问它,它只会被浏览器发送回同一服务器(实际上是源)。这对于任何其他存储都是不可能的,这意味着如果您的站点(同一来源的任何页面)中存在 XSS 漏洞,则用户令牌可能会被盗。这明显不如使用 httpOnly cookie 安全。
在现代 Web 应用程序中,这是一个可以接受的风险很多次。这主要发生在您想要将相同的令牌发送到多个服务器(源)时。使用 httpOnly cookie 是不可能的。但是,如果您的令牌存储在数据库中,那么出于架构原因,您可能不想这样做。
CSRF 问题 - 已阻止
另请注意,尽管这种设计在 headers 中发送令牌几乎默认情况下可防止 cross-site 请求伪造 (CSRF)。所以好处是你不必(太多)关心 CSRF,但这是以 XSS 影响为代价的,并且在大多数情况下超过了这个好处。
状态问题
最后一点,这不是安全问题,但使用您的设计,您的 API 将是有状态的,它将为每个客户端存储一个状态。这不是很好,因为正如您所说的那样,您将不得不去数据库检查每个请求的令牌(或者您可以深入缓存和类似的复杂性来源)。然后想象一下,如果您的服务需要在多个服务器上 load-balanced、运行 并具有多个数据库副本实例,会发生什么情况。因此,现代 API 设计的目标是无状态——不为客户端存储状态。这就是(真正的)令牌认证的亮点,令牌不需要存储到数据库中,它们本身就是真实的。这就是 token-based 身份验证真正有意义的地方,而不是在简单的情况下,普通的 session id 也可以,并且会更安全。