使用 NodeJS 服务器设计移动身份验证
Posted
技术标签:
【中文标题】使用 NodeJS 服务器设计移动身份验证【英文标题】:Design for Mobile Authentication with NodeJS server 【发布时间】:2015-09-11 14:37:24 【问题描述】:我最近为我正在制作的 ios 应用程序的安全性和用户身份验证问题苦苦挣扎,主要问题是如何允许用户使用任何 3rd 方服务(或本机用户帐户)注册并且仍然维护安全和模块化的流程。
我想出的解决方案非常复杂,我不能 100% 确定所有这些是否都是最佳实践,所以我想我会询问并获得任何关于我可以解决的问题的建议和指示,哪些行之有效,有什么不好的等等。
首先是身份验证问题。我喜欢将身份验证的想法与用户的想法分开。对我来说,身份验证是由设备或客户端执行的,独立于特定用户,用户帐户是作为身份验证的结果创建或检索的东西。这允许您将客户端的身份验证视为一个过程,然后对用户进行身份验证(检查帐户是否存在等),以便有两层安全性。例如,客户端成功验证,但用户密码错误,整体验证将失败,这两个概念松散耦合是有益的。
为了实现身份验证,出于多种原因,我在 cookie 上使用了 JWT(JSON Web 令牌)。 1)它们在移动设备上工作得更好 2)是无会话的,这使得服务器实现更容易,并且据我所知不受 CORS 攻击。在使用移动设备时,JWT 似乎是更好的解决方案。我使用了很多 npm 库,最著名的是 express-jwt 和 jsonwebtoken 在服务器端进行身份验证。
如上所述,我不仅尝试执行身份验证,还希望允许用户注册他们想要的任何第三方服务,例如 Facebook、Twitter,以减少注册过程中的用户摩擦。在考虑了一段时间并在谷歌上搜索了很多之后,我想出了身份提供者的想法,这是一种身份验证系统,其中每个“帐户类型”都被视为单独的身份提供者,并被泛化以提供诸如 access_token 之类的信息、user_id、过期数据等。身份提供者很像您在许多应用设置页面中看到的“关联帐户”。在 iOS 方面,我创建了一个抽象类,并为我想要支持的每个服务创建了一个具体的子类,FacebookIdentityProvider
、LocalIdentityProvider
(电子邮件/密码)等。
在服务器端,我使用Passport 模块来支持各种身份提供者。例如,他们有一个 facebook-token 模块,一个用于用户的电子邮件和密码等。所以我创建了一个 API 路由 /authenticate
,我的客户根据标识符字符串 local
向序列化身份提供者发出请求,facebook-token
,passport 将调用适当的子模块,以根据提供的信息对提供者进行身份验证。
总体而言,安全流程如下所示:
-
客户端检查磁盘是否有以前的 JWT 令牌(使用 Lockbox 安全存储)。
如果找到令牌,客户端会向我的
verify
端点发出请求。此端点将验证令牌是否仍然有效且尚未过期。
如果令牌尚未过期,则向客户端发送 200 并且一切顺利。如果没有,那么客户端将使用过期令牌向我的refresh_token
端点发出请求,该令牌将尝试重新发出令牌。如果失败,则客户端向我的authenticate
端点发出请求,该端点只能作为用户操作的结果调用。
如果最初在磁盘上没有找到token,和3的结尾一样,客户端必须等待用户进行身份验证。
所有这些都完成并实施后,我对一些事情仍然有些模糊。首先,我在 express-jwt 页面上阅读了一些关于撤销令牌的内容。什么决定了我何时应该撤销令牌并让用户再次登录?每次无限期过期时不断刷新他们的令牌是没有意义的。
其次,当我将序列化的身份提供者发送到服务器时,我会传递一个额外信息的字典,护照将使用这些信息来根据流程进行身份验证。如果成功,则会为该用户创建身份提供者并将其存储在数据库中。这是否足够,或者我应该对 access_token 和我从成功通话中得到的其他字段做更多的事情?特别是使用 Facebook SDK,当客户端通过应用程序进行身份验证时,我会获得一个访问令牌,然后当客户端再次通过服务器进行身份验证时,我会获得另一个令牌。
我的另一个想法是让某人集成一个 api 密钥,该密钥通过标头或查询参数与每个请求一起传递。 api 密钥将在客户端保密并受到保护。我认为这会做的是添加另一层“身份验证”,即使是尚未通过身份验证过程的客户端。只有拥有 api-key 的客户端才能首先访问我的 api,并且只有那些客户端才能尝试进行身份验证。
我的背景是正式的网络安全(我从来都不是很好),现在是全栈移动开发,所以我确实比大多数人更好地掌握了这些东西,但我觉得我好像没有发现一些潜在的危险漏洞。不幸的是,我无法发布代码,因为这是我的业务,但如果有什么我没有说清楚,请发表评论,我很乐意详细说明。
另外我觉得我应该提一下,所有这些都是通过我使用 nginx 配置的 SSL 完成的,我所有的 iOS 网络请求都是使用 Overcoat 发出的。最终我想使用 Nginx 作为负载均衡器,但这是另一天的帖子。
【问题讨论】:
这里不是 *** 的地方。 那么它属于哪里呢?说它不属于没有帮助。 如果它与更高级别的编程概念或概念性(但仍与编程有关),则应在programmers.stackexchange.com 【参考方案1】:我最近刚用过类似的东西。撤销在 JWT 中被误解,您不能“撤销”它,直到客户端请求刷新令牌,您可以拒绝对特定令牌的请求,但您不能将其从客户端设备中删除,直到它仅使用 restful 服务器过期。好吧,在客户端应用程序中,如果您从服务器收到拒绝,您当然可以删除令牌。
移动应用程序的问题,您不想打扰用户不必要地询问身份验证数据,而且如果用户丢失他的设备或更换他的设备,他/她自然想撤销旧设备的访问权限:
您可以将哈希密码保存在令牌中(加密),并且在每个请求中您可以检查令牌中保存的哈希密码是否与您数据库中用户记录中的密码相同。
您可以在 db 中使用另一个表来保存用户 ID、令牌 ID、设备信息、已撤销字段(真/假)。您只需简单地跟踪此表中已撤销的令牌,当设备在过期时使用已撤销的令牌请求刷新时,您只需返回错误,您也可以从表中删除此行,因为过期的令牌不再是问题。
希望这会有所帮助。
【讨论】:
以上是关于使用 NodeJS 服务器设计移动身份验证的主要内容,如果未能解决你的问题,请参考以下文章
在 NodeJS/Express 中使用 API 网关进行微服务 API 身份验证
成功 NodeJS 身份验证后使用 Nginx 提供静态内容
使用 nodejs Web 服务器但没有框架对用户进行身份验证
nodeJS,angularJS应用程序中页面请求的服务器身份验证