ember.js 针对身份验证和会话管理的SPA最佳做法

vq8itlhq  于 2022-11-05  发布在  其他
关注(0)|答案(3)|浏览(135)

当使用Angular、Ember、React等框架构建SPA风格的应用程序时,人们认为哪些是身份验证和会话管理的最佳实践?我可以想到几种方法来考虑解决这个问题。
1.假设API和UI具有相同的源域,则将其与常规Web应用程序的身份验证区别对待。
这可能涉及到会话cookie、服务器端会话存储和可能的一些会话API端点,通过身份验证的Web UI可以点击这些端点来获取当前用户信息,以帮助进行个性化,甚至可能确定客户端的角色/能力。服务器仍然会强制执行保护数据访问的规则,当然,UI只会使用这些信息来定制体验。
1.将其视为使用公共API的任何第三方客户端,并使用某种类似于OAuth的令牌系统进行身份验证。客户端UI将使用此令牌机制来验证向服务器API发出的每个请求。
我不是一个真正的Maven在这里,但#1似乎是完全足够的绝大多数情况下,但我真的很想听到一些更有经验的意见。

5kgi1eie

5kgi1eie1#

这个问题已经解决,在一个稍微不同的形式,在长度,在这里:
RESTful Authentication
但这是从服务器端解决的问题。让我们从客户端来看看这个问题。不过,在此之前,有一个重要的前奏:

Javascript加密是没有希望的

Matasano关于这一点的文章很有名,但其中包含的教训也非常重要:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
总结一下:

  • 中间人攻击可以很容易地将您的加密代码替换为<script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
  • 对于通过非SSL连接提供任何资源的页面,中间人攻击是微不足道的。
  • 一旦你有了SSL,你就可以使用真实的的加密了。

再加上我自己的一个推论:

  • 成功的XSS攻击可能导致攻击者在您客户端的浏览器上执行代码,即使您使用SSL --因此,即使您已将每一个舱口都封好,如果您的攻击者找到了在其他人的浏览器上执行任何javascript代码的方法,您的浏览器加密仍可能失败。

如果您打算使用JavaScript客户端,这会使许多RESTful身份验证方案变得不可能或愚蠢。

HTTP基本身份验证

首先,HTTP基本身份验证。最简单的方案:只需在每个请求中传递一个用户名和密码。
当然,这绝对需要SSL,因为你在每个请求中传递的都是Base64(可逆)编码的用户名和密码。任何人在线路上监听都可以轻松地提取用户名和密码。大多数“基本身份验证不安全”的论点都来自于“HTTP上的基本身份验证”,这是一个糟糕的想法。
浏览器提供了内置的HTTP Basic Auth支持,但它非常丑陋,你可能不应该在你的应用程序中使用它。
这是最具REST风格的解决方案。服务器不需要知道任何状态,并且对与用户的每一次交互都进行身份验证。(大多数是稻草人)坚持认为,保持任何形式的状态都是异端,如果你想到任何其他的身份验证方法,你就会口吐白沫。你可以将你的对象作为文件存储在由.htaccess文件保护的文件夹中,如果你愿意的话!

问题?你在客户端缓存了用户名和密码。这给了evil.ru一个更好的破解方法--即使是最基本的XSS漏洞也可能导致客户端将他的用户名和密码发送到一个恶意的服务器。你可以尝试通过散列和盐处理密码来减轻这种风险,但是记住:JavaScript Crypto是没有希望的。您可以通过将其留给浏览器的Basic Auth支持来减轻此风险,但是..如前所述,非常丑陋。

HTTP摘要验证

Is Digest authentication possible with jQuery?
一个更“安全”的认证,这是一个请求/响应哈希挑战。除了JavaScript Crypto是无望的,所以它只能在SSL上工作,你仍然必须在客户端缓存用户名和密码,这使得它比HTTP基本认证更复杂,但 * 没有更安全 *。

使用其他签名参数进行查询验证。

另一种更“安全”的身份验证,使用随机数和定时数据加密参数(以防止重复和定时攻击),然后发送。最好的例子之一是OAuth 1.0协议,据我所知,它是在REST服务器上实现身份验证的一种非常出色的方式。
https://www.rfc-editor.org/rfc/rfc5849
哦,但是JavaScript没有任何OAuth 1.0客户端。为什么?

JavaScript Crypto是没有希望的,请记住。JavaScript没有SSL就不能参与OAuth 1.0,并且您仍然必须在本地存储客户端的用户名和密码-这将其与Digest Auth归为同一类-它比HTTP Basic Auth更复杂,但它 * 并不更安全 *。

令牌

用户发送用户名和密码,并在交换中获得可用于对请求进行身份验证的令牌。
这比HTTP Basic Auth稍微安全一些,因为用户名/密码事务一完成,您就可以丢弃敏感数据。它也不太RESTful,因为令牌构成了“状态”,使服务器实现更加复杂。
SSL静态图像
不过,麻烦的是,您仍然需要发送初始用户名和密码来获取令牌。敏感信息仍然会触及您的易受损害的JavaScript。
为了保护用户的凭据,您仍然需要防止攻击者进入JavaScript,并且您仍然需要通过网络发送用户名和密码。

令牌到期

实施令牌策略很常见,例如“嘿,当此令牌存在时间过长时,丢弃它并让用户重新进行身份验证。”或“我非常确定允许使用此令牌的唯一IP地址是XXX.XXX.XXX.XXX“。这些策略中的许多都是非常好的想法。
火羊
但是,使用不带SSL的令牌仍然容易受到称为“sidejacking”的攻击:http://codebutler.github.io/firesheep/

攻击者没有获得您的用户凭据,但他们仍然可以假装是您的用户,这可能非常糟糕。
tl;dr:通过网络发送未加密的令牌意味着攻击者可以很容易地获取这些令牌并冒充你的用户。FireSheep是一个可以很容易地做到这一点的程序。

一个单独的、更安全的区域

您运行的应用程序越大,就越难绝对确保他们无法注入某些代码来改变您处理敏感数据的方式。您是否绝对信任您的CDN?您的广告商?您自己的代码库?
常见于信用卡详细信息,而不太常见于用户名和密码-一些实现者将“敏感数据输入”与应用程序的其余部分放在一个单独的页面上,该页面可以尽可能严格控制和锁定,最好是难以对用户进行网络钓鱼的页面。

Cookie(仅表示令牌)

将认证令牌放在cookie中是可能的(也是常见的)。这并不会改变带有令牌的auth的任何属性,它更方便一些。前面的所有参数仍然适用。

会话(仍仅表示令牌)

会话身份验证只是令牌身份验证,但有一些差异,使它看起来像是一个略有不同的东西:

  • 用户从未经身份验证的令牌开始。
  • 后端维护一个绑定到用户令牌的“状态”对象。
  • 该令牌在Cookie中提供。
  • 应用程序环境会将细节抽象化。

除此之外,它与令牌授权没有什么不同。
这与RESTful实现的差距甚至更大--使用状态对象,您将在有状态服务器上的普通ol' RPC的道路上越走越远。

开放式身份验证2.0

OAuth 2.0关注的问题是“软件A如何给予软件B访问用户X的数据,而软件B却不能访问用户X的登录凭证”。
这种实现方式在很大程度上只是一种标准的方式,用户可以获得令牌,然后第三方服务可以“是的,这个用户和这个令牌匹配,你现在可以从我们这里获得他们的一些数据。”
从根本上说,OAuth 2.0只是一个令牌协议,它表现出与其他令牌协议相同的特性--仍然需要SSL来保护这些令牌--只是改变了这些令牌的生成方式。
OAuth 2.0可以通过两种方式帮助您:

  • 向他人提供身份验证/信息
  • 从其他人获取身份验证/信息

但归根结底你只是...使用代币

返回您的问题

因此,您要问的问题是“我是应该将令牌存储在Cookie中,并让环境的自动会话管理来处理细节,还是应该将令牌存储在Javascript中,并自己处理这些细节?”
而答案是:* 做任何让你开心的事 *
不过,自动会话管理的好处是,在幕后有很多神奇的事情在发生。通常情况下,自己控制这些细节会更好。

我21岁,所以SSL是肯定的

对方的回答是:一切都使用https,否则强盗会窃取用户的密码和令牌。

mu0hgdu0

mu0hgdu02#

您可以使用JWT (JSON Web令牌) 和SSL/HTTPS来提高身份验证过程的安全性。
基本身份验证/会话ID可通过以下方式窃取:

  • MITM攻击(中间人攻击)- * 不使用SSL/HTTPS*
  • 入侵者获得对用户计算机的访问权限
  • XSS系统

通过使用JWT,您可以对用户的身份验证详细信息进行加密,并将其存储在客户机中,然后将其与每个请求沿着发送到API,服务器/API在API中验证令牌。如果没有私钥(服务器/API秘密存储),令牌将无法被解密/读取Read update

新的(更安全的)流将是:

登录

  • 用户登录并将登录凭据发送到API (通过SSL/HTTPS)
  • API接收登录凭据
  • 如果有效:
  • 在数据库中注册新会话读取更新
  • 使用私钥加密JWT中的用户ID、会话ID、IP地址、时间戳等。
  • API将JWT标记发送回客户端 (通过SSL/HTTPS)
  • 客户机接收JWT标记并将其存储在localStorage/cookie中

对API的每个请求

  • 用户向API (通过SSL/HTTPS) 发送HTTP请求,并在HTTP标头中存储JWT标记
  • API读取HTTP标头并使用其私钥解密JWT标记
  • API验证JWT标记,将HTTP请求中的IP地址与JWT标记中的IP地址进行匹配,并检查会话是否已过期
  • 如果有效:
  • 返回包含请求内容的响应
  • 如果无效:
  • 抛出异常(403 / 401)
  • 标记系统中的入侵
  • 向用户发送警告电子邮件。
    2015年7月30日更新日期:

JWT有效负载/声明实际上可以在没有私钥(秘密)的情况下被读取,并且将其存储在localStorage中是不安全的。对于这些错误的声明,我很抱歉。但是,它们似乎在JWE standard (JSON Web Encryption)上工作。
我通过存储声明来实现这一点(userID,exp),并使用私钥对其进行签名(秘密)API/后端只知道它,并将其作为安全的HttpOnly cookie存储在客户机上。这样,它就不能通过XSS读取,也不能被操纵,否则JWT将无法通过签名验证。同样,通过使用 secure HttpOnly cookie,您要确保cookie仅通过HTTP请求(脚本无法访问)发送,并且仅通过安全连接(HTTPS)发送。

2016年7月17日更新日期:

JWT本质上是无状态的。这意味着它们会使自己失效/过期。通过在令牌的声明中添加SessionID,您可以使它具有状态,因为它的有效性现在不仅取决于签名验证和过期日期,还取决于服务器上的会话状态。然而,好处是您可以轻松地使令牌/会话失效,而这在以前的无状态JWT中是无法做到的。

k75qkfdt

k75qkfdt3#

我会选择第二种,代币系统。
您知道ember-authember-simple-auth吗?它们都使用基于令牌的系统,如ember-simple-auth状态:
用于在Ember.js应用程序中实现基于令牌的身份验证的轻量级、不引人注目的库。http://ember-simple-auth.simplabs.com
它们具有会话管理功能,并且也很容易插入到现有项目中。
还有一个Ember App Kit示例版本的ember-simple-auth:Working example of ember-app-kit using ember-simple-auth for OAuth2 authentication.

相关问题