SPA认证和会话管理的最佳做法

问题描述:

使用Angular,Ember,React等框架构建SPA风格的应用程序时,人们认为是认证和会话管理的最佳实践?我可以想到几种方法来考虑这个问题。

When building SPA style applications using frameworks like Angular, Ember, React, etc. what do people believe to be some best practices for authentication and session management? I can think of a couple of ways of considering approaching the problem.


  1. 对待它与使用常规Web应用程序的身份验证的区别假设API和UI具有相同的起始域。

  1. Treat it no differently than authentication with a regular web application assuming the API and and UI have the same origin domain.

这可能涉及到会话cookie,服务器端会话存储以及可能的一些会话API端点,经过身份验证的Web UI可以获取当前用户信息以帮助个性化或者甚至可以在客户端确定角色/能力。服务器仍然会执行保护数据访问权限的规则,UI只会使用这些信息来定制体验。

This would likely involve having a session cookie, server side session storage and probably some session API endpoint that the authenticated web UI can hit to get current user information to help with personalization or possibly even determining roles/abilities on the client side. The server would still enforce rules protecting access to data of course, the UI would just use this information to customize the experience.

像任何第三方客户端使用公共API,并使用与OAuth类似的某种令牌系统进行身份验证。客户端UI将使用该令牌机制来验证对服务器API的每个请求。

Treat it like any third-party client using a public API and authenticate with some sort of token system similar to OAuth. This token mechanism would used by the client UI to authenticate each and every request made to the server API.

这不是一个专家,但#1似乎对绝大多数情况来说完全是足够的,但我真的很想听到更多有经验的意见。

I'm not really much of an expert here but #1 seems to be completely sufficient for the vast majority of cases, but I'd really like to hear some more experienced opinions.

这个问题的解决方式略有不同,这里是:

This question has been addressed, in a slightly different form, at length, here:

验证身份验证

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

But this addresses it from the server-side. Let's look at this from the client-side. Before we do that, though, there's an important prelude:

Matasano的文章是有名的,但其中包含的教训非常重要:

Matasano's article on this is famous, but the lessons contained therein are pretty important:

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

总结:


  • 中间人攻击可以用< script>
    函数hash_algorithm(password){lol_nope_send_it_to_me_instead(password); }< / script>

  • 一个中间人的攻击对于通过非SSL连接为任何资源提供的页面是微不足道的。 / li>
  • 一旦你有SSL,你就会使用真正的加密。

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

And to add a corollary of my own:


  • 即使您使用SSL,成功的XSS攻击可能会导致攻击者在客户端的浏览器上执行代码 - 所以即使你已经把每个舱口压下来,你的浏览器加密仍然可以失败,如果你的攻击者找到一种方法来执行任何JavaScript代码在别人的浏览器。

如果您打算使用JavaScript客户端,则会使许多RESTful认证方案变得不可能或愚蠢。我们看看吧!

This renders a lot of RESTful authentication schemes impossible or silly if you're intending to use a JavaScript client. Let's look!

首先,HTTP Basic Auth。最简单的方案:只需传递每个请求的名称和密码。

First and foremost, HTTP Basic Auth. The simplest of schemes: simply pass a name and password with every request.

这当然绝对需要SSL,因为你传递一个Base64(可逆地)编码每个请求的名称和密码。任何在线听的人都可以简单地提取用户名和密码。大多数基本认证是不安全的论据来自基本认证通过HTTP的地方,这是一个可怕的想法。

This, of course, absolutely requires SSL, because you're passing a Base64 (reversibly) encoded name and password with every request. Anybody listening on the line could extract username and password trivially. Most of the "Basic Auth is insecure" arguments come from a place of "Basic Auth over HTTP" which is an awful idea.

浏览器提供烘焙的HTTP Basic Auth支持,但它是丑陋的罪恶,您可能不应该将其用于您的应用程序。另一种方法是在JavaScript中隐藏用户名和密码。

The browser provides baked-in HTTP Basic Auth support, but it is ugly as sin and you probably shouldn't use it for your app. The alternative, though, is to stash username and password in JavaScript.

这是最REST风格的解决方案。服务器不需要任何状态知识,并且验证与用户的每个单独的交互。一些REST爱好者(主要是稻草人)坚持认为,如果您想到任何其他身份验证方法,维持任何形式的国家是异端的,并会在嘴里发泡。这种符合标准的理论有益 - 它由Apache开箱即用,您可以将您的对象作为文件保存在.htaccess文件夹的文件夹中,如果您的心脏需要!

This is the most RESTful solution. The server requires no knowledge of state whatsoever and authenticates every individual interaction with the user. Some REST enthusiasts (mostly strawmen) insist that maintaining any sort of state is heresy and will froth at the mouth if you think of any other authentication method. There are theoretical benefits to this sort of standards-compliance - it's supported by Apache out of the box - you could store your objects as files in folders protected by .htaccess files if your heart desired!

问题?您正在客户端缓存用户名和密码。这给evil.ru一个更好的破解 - 即使是最基本的XSS漏洞可能会导致客户端将他的用户名和密码发送到一个邪恶的服务器。您可以尝试通过散列和解密密码来缓解这种风险,但请记住: JavaScript加密是绝对的。您可以通过将浏览器的基本认证支持留给浏览器的基本认证支持来减轻这种风险,但是如前所述,丑化为罪。

The problem? You are caching on the client-side a username and password. This gives evil.ru a better crack at it - even the most basic of XSS vulnerabilities could result in the client beaming his username and password to an evil server. You could try to alleviate this risk by hashing and salting the password, but remember: JavaScript Crypto is Hopeless. You could alleviate this risk by leaving it up to the Browser's Basic Auth support, but.. ugly as sin, as mentioned earlier.

使用jQuery可以进行摘要认证吗?

一个更安全的认证,这是一个请求/响应哈希挑战。除了 JavaScript Crypto是绝对的,因此它只能在SSL上工作,您仍然必须在客户端缓存用户名和密码,使其比HTTP Basic Auth更复杂,但不再安全

A more "secure" auth, this is a request/response hash challenge. Except JavaScript Crypto is Hopeless, so it only works over SSL and you still have to cache the username and password on the client side, making it more complicated than HTTP Basic Auth but no more secure.

另一个更安全的身份验证使用随机数和时序数据加密您的参数(以防止重复和定时攻击)并发送。其中最好的例子之一是OAuth 1.0协议,据我所知,这是一种在REST服务器上实现身份验证的非常棒的方式。

Another more "secure" auth, where you encrypt your parameters with nonce and timing data (to protect against repeat and timing attacks) and send the. One of the best examples of this is the OAuth 1.0 protocol, which is, as far as I know, a pretty stonking way to implement authentication on a REST server.

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

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

Oh, but there aren't any OAuth 1.0 clients for JavaScript. Why?

JavaScript加密是绝望的,请记住。 JavaScript无法在没有SSL的情况下参与OAuth 1.0,而您仍然需要在本地存储客户端的用户名和密码 - 这将其与Digest Auth类似,这比HTTP Basic Auth更复杂,但它不再安全。

JavaScript Crypto is Hopeless, remember. JavaScript can't participate in OAuth 1.0 without SSL, and you still have to store the client's username and password locally - which puts this in the same category as Digest Auth - it's more complicated than HTTP Basic Auth but it's no more secure.

用户发送用户名和密码,交换获取可用于验证请求

The user sends a username and password, and in exchange gets a token that can be used to authenticate requests.

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

This is marginally more secure than HTTP Basic Auth, because as soon as the username/password transaction is complete you can discard the sensitive data. It's also less RESTful, as tokens constitute "state" and make the server implementation more complicated.

虽然是,但您仍然必须发送初始用户名和密码才能获得一个令牌敏感信息仍然触及到您的妥协JavaScript。

The rub though, is that you still have to send that initial username and password to get a token. Sensitive information still touches your compromisable JavaScript.

为了保护用户的凭据,您仍然需要将攻击者从JavaScript中删除,您仍然需要通过电话发送用户名和密码。 SSL必需。

To protect your user's credentials, you still need to keep attackers out of your JavaScript, and you still need to send a username and password over the wire. SSL Required.

通常执行令牌策略,如嘿,当这个令牌已经过长时间,丢弃它并使用户再次进行身份验证。或者我很确定允许使用这个令牌的唯一IP地址是 XXX.XXX.XXX.XXX 。许多这些政策是相当不错的想法。

It's common to enforce token policies like "hey, when this token has been around too long, discard it and make the user authenticate again." or "I'm pretty sure that the only IP address allowed to use this token is XXX.XXX.XXX.XXX". Many of these policies are pretty good ideas.

然而,使用没有SSL的令牌仍然很脆弱发起一个名为'sidejacking'的攻击: http://codebutler.github.io/firesheep/

However, using a token Without SSL is still vulnerable to an attack called 'sidejacking': http://codebutler.github.io/firesheep/

攻击者没有获取用户的凭据,但是他们仍然可以假装成为您的用户,这可能非常糟糕。

The attacker doesn't get your user's credentials, but they can still pretend to be your user, which can be pretty bad.

tl; dr:通过电子邮件发送未加密的令牌意味着攻击者可以轻松地删除这些令牌,并假装成为您的用户。 FireSheep是一个非常简单的程序。

tl;dr: Sending unencrypted tokens over the wire means that attackers can easily nab those tokens and pretend to be your user. FireSheep is a program that makes this very easy.

您运行的应用程序越大,越难以确保他们无法注入一些更改处理敏感数据的代码。你绝对相信你的CDN吗?您的广告商?你自己的代码库?

The larger the application that you're running, the harder it is to absolutely ensure that they won't be able to inject some code that changes how you process sensitive data. Do you absolutely trust your CDN? Your advertisers? Your own code base?

通用的信用卡详细信息,用户名和密码不常见 - 一些实施者在其他应用程序的单独页面上保持敏感数据输入,页面可以尽可能地严格控制和锁定,优选地是难以用户化的用户。

Common for credit card details and less common for username and password - some implementers keep 'sensitive data entry' on a separate page from the rest of their application, a page that can be tightly controlled and locked down as best as possible, preferably one that is difficult to phish users with.

将身份验证令牌放在曲奇饼。这不会改变使用令牌的auth的任何属性,这更是一个方便的事情。所有以前的论据仍然适用。

It is possible (and common) to put the authentication token in a cookie. This doesn't change any of the properties of auth with the token, it's more of a convenience thing. All of the previous arguments still apply.

会话Auth只是令牌身份验证,但有一些区别使它看起来有点不一样:

Session Auth is just Token authentication, but with a few differences that make it seem like a slightly different thing:


  • 用户从未经身份验证的令牌开始。

  • 后端维护一个与用户令牌绑定的状态对象。

  • 令牌在cookie中提供。

  • 应用程序环境摘录细节远离你。

  • Users start with an unauthenticated token.
  • The backend maintains a 'state' object that is tied to a user's token.
  • The token is provided in a cookie.
  • The application environment abstracts the details away from you.

除此之外,真的没有什么不同于Token Auth。

Aside from that, though, it's no different from Token Auth, really.

从一个RESTful实现中进一步徘徊,状态对象将进一步向下进一步向下移动状态服务器上的简单RPC的路径。

This wanders even further from a RESTful implementation - with state objects you're going further and further down the path of plain ol' RPC on a stateful server.

OAuth 2.0查看软件A如何给予软件B访问用户X的数据没有软件B可以访问用户X的登录凭据。

OAuth 2.0 looks at the problem of "How does Software A give Software B access to User X's data without Software B having access to User X's login credentials."

实现非常仅仅是用户获取令牌的标准方式,然后为第三方服务,这个用户和这个令牌匹配,你现在可以从我们那里得到一些我们的数据。

The implementation is very much just a standard way for a user to get a token, and then for a third party service to go "yep, this user and this token match, and you can get some of their data from us now."

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

Fundamentally, though, OAuth 2.0 is just a token protocol. It exhibits the same properties as other token protocols - you still need SSL to protect those tokens - it just changes up how those tokens are generated.

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

There are two ways that OAuth 2.0 can help you:


  • 向他人提供身份验证/信息

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

但是当它归结到它时,你只是...使用令牌。

But when it comes down to it, you're just... using tokens.

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

So, the question that you're asking is "should I store my token in a cookie and have my environment's automatic session management take care of the details, or should I store my token in Javascript and handle those details myself?"

答案是:做任何让你快乐的事情

然而,关于自动会话管理的事情是,幕后有很多魔法。通常自己更好地控制这些细节。

The thing about automatic session management, though, is that there's a lot of magic happening behind the scenes for you. Often it's nicer to be in control of those details yourself.

另一个答案是:使用https,您的用户密码和令牌。

The other answer is: Use https for everything or brigands will steal your users' passwords and tokens.