SPAauthentication和会话pipe理的最佳实践

当使用Angular,Ember,React等框架构buildSPA风格的应用程序时,人们认为什么是authentication和会话pipe理的最佳实践? 我可以考虑几种考虑解决问题的方法。

  1. 假设API和UI具有相同的原始域,对待它与对常规Web应用程序进行authentication没有区别。

    这可能涉及具有会话cookie,服务器端会话存储和可能的一些会话API端点,authentication的web UI可以获得当前用户信息以帮助个性化或者甚至可以确定客户端上的angular色/能力。 服务器仍然会执行保护数据访问的规则,UI将只使用这些信息来定制体验。

  2. 像使用公共API的任何第三方客户端一样对待它,并使用类似于OAuth的某种令牌系统进行身份validation。 客户端UI使用此令牌机制来validation向服务器API发出的每个请求。

我在这里并不是什么专家,但是绝大多数情况下#1似乎已经完全够用了,但是我真的很想听听一些更有经验的意见。

这个问题已经在稍微有些不同的forms下得到了解答:

RESTfulauthentication

但是这从服务器端来解决它。 我们从客户端来看这个。 在我们这样做之前,有一个重要的前奏:

Javascript Crypto是绝望的

Matasano在这方面的文章是有名的,但其中的教训是非常重要的:

http://www.matasano.com/articles/javascript-cryptography/

总结:

  • 中间人攻击可以用<script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>来代替你的encryption代码<script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script> <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
  • 中间人攻击对于通过非SSL连接提供资源的页面是微不足道的。
  • 一旦你有SSL,反正你使用真正的密码。

并添加一个我自己的推论:

  • 一个成功的XSS攻击可能导致攻击者在您的客户端浏览器上执行代码,即使您使用的是SSL – 即使您已经将所有的孵化器都closures了,如果攻击者find执行方法,浏览器encryption仍然可能失败任何其他人的浏览器上的JavaScript代码。

这使得如果您打算使用JavaScript客户端,很多RESTfulauthenticationscheme是不可能的或者很愚蠢的。 我们看看吧!

HTTP基本身份validation

首先,HTTP基本身份validation。 最简单的scheme:简单地通过每个请求传递一个名称和密码。

当然,这绝对需要SSL,因为每个请求都传递一个Base64(可逆)编码的名称和密码。 任何听线的人都可以简单地提取用户名和密码。 大部分“基本身份validation是不安全的”参数来自“基于HTTP的基本身份validation”,这是一个可怕的想法。

浏览器提供了支持HTTP基本身份validation的function,但是它很丑陋,您可能不应该将它用于您的应用程序。 不过,替代方法是在JavaScript中存储用户名和密码。

这是最RESTful的解决scheme。 服务器不需要知道任何状态,并且authentication与用户的每个单独的交互。 一些REST爱好者(大多数是稻草人)坚持认为,维持任何状态都是异端邪说,如果想到其他任何authentication方法,都会在口中发泡。 这样的标准符合性有理论上的好处 – 开箱即用的Apache支持 – 如果你的心想要的话,你可以将你的对象作为文件保存在.htaccess文件保护的文件夹中!

这个问题 ? 您正在客户端caching用户名和密码。 这给了evil.ru一个更好的破解 – 即使是最基本的XSS漏洞可能导致客户端将他的用户名和密码发送到邪恶的服务器。 您可以尝试通过散列和腌制密码来缓解这种风险,但请记住: JavaScript Crypto是绝望的 。 您可以通过将其留给浏览器的基本身份validation支持来缓解这种风险,但是像前面提到的那样丑陋像罪恶一样。

HTTP摘要validation

Digestvalidation可能与jQuery?

一个更“安全”的authentication,这是一个请求/响应哈希挑战。 除了JavaScript Crypto是绝望的 ,所以它只能在SSL上工作,而且你仍然需要在客户端caching用户名和密码,使得它比HTTP Basic Auth更复杂,但没有更多的安全

使用附加签名参数查询身份validation。

另一个更“安全”的身份validation,在那里你encryption你的参数随机数和时间数据(以防止重复和定时攻击),并发送。 其中一个最好的例子就是OAuth 1.0协议,据我所知,这是一种在REST服务器上实现身份validation的相当惊人的方法。

http://tools.ietf.org/html/rfc5849

哦,但没有任何JavaScript的OAuth 1.0客户端。 为什么?

记住, JavaScriptencryption是绝望的 。 JavaScript无法在不使用SSL的情况下参与OAuth 1.0,而且您仍然必须在本地存储客户端的用户名和密码 – 这与“摘要身份validation”相同 – 它比HTTP基本身份validation更复杂,但并不安全

代币

用户发送一个用户名和密码,并作为交换获得一个可用于authentication请求的令牌。

这比HTTP Basic Auth更安全,因为一旦用户名/密码交易完成,您可以放弃敏感数据。 由于令牌构成“状态”并使得服务器实现更复杂,所以它也不太RESTful。

SSL仍然

尽pipe如此,你仍然需要发送初始的用户名和密码才能获得令牌。 敏感信息仍然触及您的可折中的JavaScript。

为了保护您的用户的凭据,您仍然需要阻止攻击者脱离JavaScript,并且仍然需要通过线路发送用户名和密码。 需要SSL。

令牌到期

执行令牌策略是很常见的,例如“当这个令牌已经存在很长时间了,丢弃它并且让用户再次进行authentication”。 或者“我确定唯一允许使用此令牌的IP地址是XXX.XXX.XXX.XXX ”。 许多这些政策是非常好的想法。

Firesheeping

但是,使用不带SSL的标记仍然容易受到“sidejacking”的攻击: http ://codebutler.github.io/firesheep/

攻击者没有得到你的用户的凭据,但他们仍然可以伪装成你的用户,这可能是非常糟糕的。

tl; dr:通过电子邮件发送未encryption的标记意味着攻击者可以轻松地戳记这些标记并假装成您的用户。 FireSheep是一个非常简单的程序。

独立的,更安全的区域

您运行的应用程序越大,绝对确保他们将无法注入一些代码,从而改变处理敏感数据的方式。 你完全相信你的CDN吗? 您的广告客户? 你自己的代码库?

通常用于信用卡详细信息,用户名和密码不太常见 – 有些实施者将“敏感数据input”与应用程序的其余部分保持在一个单独的页面上,这个页面可以被严格控制和尽可能最好地locking,很难用networking钓鱼用户。

Cookie(只是表示令牌)

将身份validation令牌放在cookie中是可能的(也是常见的)。 这不会改变令牌的任何auth属性,这更方便。 所有以前的论点仍然适用。

会话(仍然只是表示令牌)

会话身份validation只是令牌身份validation,但有一些差异,使它看起来像一个稍微不同的事情:

  • 用户从未经身份validation的标记开始。
  • 后端维护一个绑定到用户令牌的“状态”对象。
  • 令牌在cookie中提供。
  • 应用程序环境将您的详细信息抽象出来。

除此之外,真的,它与Token Auth没有区别。

这更远离了RESTful实现 – 使用状态对象,您将远离“有状态服务器上普通的RPC”path。

OAuth 2.0

OAuth 2.0着眼于“软件A如何让软件B访问用户X的数据而没有软件B访问用户X的login凭证”的问题。

这个实现对于用户来说是一个标准的获取令牌的方法,然后对于第三方服务来说,“是的,这个用户和这个令牌是匹配的,现在你可以从我们这里获得他们的一些数据。

但是从根本上说,OAuth 2.0只是一个令牌协议。 它具有与其他令牌协议相同的属性 – 您仍然需要SSL来保护这些令牌 – 它只是改变了这些令牌的生成方式。

OAuth 2.0有两种方法可以帮助您:

  • 向他人提供authentication/信息
  • 从别人那里获得authentication/信息

但是当它来到它,你只是…使用令牌。

回到你的问题

所以,你所问的问题是“我是否应该将自己的令牌存储在cookie中,让我的环境的自动会话pipe理负责细节处理,还是应该将自己的令牌存储在Javascript中,并自己处理这些细节?

答案是: 做任何事情让你开心

关于自动会话pipe理的事情是,幕后有很多魔术发生在你身上。 通常自己控制这些细节更好。

我21岁,所以SSL是肯定的

另一个答案是:使用https的一切或盗贼会窃取你的用户的密码和令牌。

您可以使用JWT (JSON Web令牌)和SSL / HTTPS来提高身份validation过程的安全性。

基本身份validation/会话ID可以通过以下方式被盗取:

  • 中间人攻击(Man-In-The-Middle) – 没有SSL / HTTPS
  • 入侵者获得访问用户的计算机
  • XSS

通过使用JWT,您正在encryption用户的身份validation详细信息并存储在客户端中,并将其与每个请求一起发送到API,其中服务器/ APIvalidation令牌。 没有私钥(服务器/ API秘密存储) 读取更新 不能被解密/读取

新(更安全)的stream量将是:

login

  • 用户login并将login凭据发送到API (通过SSL / HTTPS)
  • API接收login凭证
  • 如果有效:
    • 在数据库中注册一个新的会话Read update
    • 使用私钥在JWT中encryption用户ID,会话ID,IP地址,时间戳等。
  • API将JWT令牌发送回客户端(通过SSL / HTTPS)
  • 客户端收到JWT令牌并存储在localStorage / cookie中

API的每个请求

  • 用户使用HTTP头中存储的JWT令牌向API (通过SSL / HTTPS)发送HTTP请求
  • API读取HTTP头并使用其私钥解密JWT令牌
  • APIvalidationJWT令牌,将HTTP请求中的IP地址与JWT令牌中的IP地址进行匹配,并检查会话是否已过期
  • 如果有效:
    • 返回请求的内容
  • 如果无效:
    • 抛出exception(403/401)
    • 在系统中标记入侵
    • 向用户发送警告电子邮件。

更新30.07.15:

JWT有效载荷/声明实际上可以在没有私钥(秘密)的情况下读取,并且将其存储在localStorage中是不安全的。 对于这些虚假陈述我感到抱歉。 不过他们似乎正在使用JWE标准(JSON Web Encryption)

我通过在JWT中存储声明(userID,exp)来实现这一点,使用API​​ /后端仅知道的私钥(秘密)对其进行签名,并将其作为安全的HttpOnly cookie存储在客户端上。 这样它不能通过XSS读取,不能被操纵,否则智威汤逊签名validation失败。 同样,通过使用安全的HttpOnly cookie,您可以确保cookie仅通过HTTP请求(脚本无法访问)发送,并且只能通过安全连接(HTTPS)发送。

更新17.07.16:

智威汤逊本质上是无国界的。 这意味着他们失效/失效。 通过在令牌的声明中添加SessionID,使其成为有状态的,因为它的有效性现在不仅仅取决于签名validation和有效期限,还取决于服务器上的会话状态。 然而好处是你可以很容易地使令牌/会话无效,这是你之前用无状态的智威汤逊所无法做到的。

我会去第二个,令牌系统。

您是否知道ember-auth或者ember-simple-auth ? 它们都使用基于标记的系统,如ember-simple-auth状态:

Ember.js应用程序中用于实现基于令牌的身份validation的轻量级和不显眼的库。 http://ember-simple-auth.simplabs.com

他们有会话pipe理,也很容易插入现有的项目。

还有一个Ember App Kit示例版本的ember-simple-auth: 使用ember-simple-auth进行OAuth2身份validation的ember-app-kit的工作示例。