这个问题已经以稍微不同的形式详细地解决了,在这里:
RESTful Authentication
但这从服务器端解决了它。让我们从客户端来看这个。不过,在我们这样做之前,有一个重要的前奏:
Javascript Crypto 是绝望的
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 支持,但它很丑陋,您可能不应该将它用于您的应用程序。不过,另一种方法是将用户名和密码存储在 JavaScript 中。
这是最 RESTful 的解决方案。服务器不需要任何状态知识,并验证与用户的每一次交互。一些 REST 爱好者(主要是稻草人)坚持认为,维护任何一种状态都是异端邪说,如果您想到任何其他身份验证方法,就会在嘴边冒泡。这种标准合规性有理论上的好处——它由 Apache 开箱即用地支持——如果你愿意的话,你可以将你的对象作为文件存储在受 .htaccess 文件保护的文件夹中!
问题?您正在客户端缓存用户名和密码。这让 evil.ru 可以更好地破解它——即使是最基本的 XSS 漏洞也可能导致客户端将他的用户名和密码发送到恶意服务器。您可以尝试通过散列和加盐密码来减轻这种风险,但请记住:JavaScript Crypto is Hopeless。您可以通过将其留给浏览器的基本身份验证支持来减轻这种风险,但是......如前所述,丑陋至极。
HTTP 摘要验证
Is Digest authentication possible with jQuery?
更“安全”的身份验证,这是一个请求/响应哈希挑战。除了 JavaScript Crypto is Hopeless,它只在 SSL 上工作,你仍然需要在客户端缓存用户名和密码,这使得它比 HTTP Basic Auth 更复杂,但 没有更安全。
使用附加签名参数查询身份验证。
另一种更“安全”的身份验证,您可以在其中使用 nonce 和计时数据加密您的参数(以防止重复和计时攻击)并发送。最好的例子之一是 OAuth 1.0 协议,据我所知,这是在 REST 服务器上实现身份验证的一种非常棒的方式。
https://www.rfc-editor.org/rfc/rfc5849
哦,但是没有任何用于 JavaScript 的 OAuth 1.0 客户端。为什么?
JavaScript Crypto is Hopeless,记住。 JavaScript 无法在没有 SSL 的情况下参与 OAuth 1.0,并且您仍然必须在本地存储客户端的用户名和密码 - 这与 Digest Auth 属于同一类别 - 它比 HTTP Basic Auth 更复杂,但它并不安全.
令牌
用户发送用户名和密码,作为交换获得可用于验证请求的令牌。
这比 HTTP Basic Auth 稍微安全一些,因为一旦用户名/密码事务完成,您就可以丢弃敏感数据。它也不太 RESTful,因为令牌构成“状态”并使服务器实现更加复杂。
SSL 仍然
但问题在于,您仍然必须发送初始用户名和密码才能获得令牌。敏感信息仍会触及您的可妥协 JavaScript。
为了保护您的用户凭据,您仍然需要阻止攻击者访问您的 JavaScript,并且您仍然需要通过网络发送用户名和密码。需要 SSL。
令牌到期
强制执行令牌策略很常见,例如“嘿,当此令牌存在时间过长时,将其丢弃并让用户再次进行身份验证。”或“我很确定允许使用此令牌的唯一 IP 地址是 XXX.XXX.XXX.XXX”。其中许多政策都是非常好的想法。
火羊
但是,使用没有 SSL 的令牌仍然容易受到称为“sidejacking”的攻击:http://codebutler.github.io/firesheep/
攻击者没有获得您用户的凭据,但他们仍然可以伪装成您的用户,这可能非常糟糕。
tl;dr:通过网络发送未加密的令牌意味着攻击者可以轻松获取这些令牌并伪装成您的用户。 FireSheep 是一个让这一切变得非常简单的程序。
一个独立的、更安全的区域
您运行的应用程序越大,就越难绝对确保他们无法注入一些代码来改变您处理敏感数据的方式。你绝对信任你的 CDN 吗?你的广告商?你自己的代码库?
信用卡详细信息很常见,而用户名和密码不太常见 - 一些实施者将“敏感数据输入”保留在与其应用程序的其余部分不同的页面上,该页面可以尽可能严格控制和锁定,最好是一个难以钓鱼用户的。
Cookie(仅指代币)
将身份验证令牌放在 cookie 中是可能的(并且很常见)。这不会使用令牌更改任何 auth 的属性,它更方便。前面的所有论点仍然适用。
Session(仍然只是表示Token)
Session Auth 只是 Token 身份验证,但有一些差异使它看起来有点不同:
- 用户从未经身份验证的令牌开始。
- 后端维护一个与用户令牌相关联的“状态”对象。
- 令牌在 cookie 中提供。
- 应用程序环境从您那里抽象出细节。
除此之外,它与 Token Auth 并没有什么不同,真的。
这与 RESTful 实现相差甚远 - 使用状态对象,您将在有状态服务器上的普通 ol' RPC 路径上走得更远。
OAuth 2.0
OAuth 2.0 着眼于“软件 A 如何在软件 B 无法访问用户 X 的登录凭据的情况下让软件 B 访问用户 X 的数据”的问题。
实现只是用户获取令牌的标准方式,然后让第三方服务去“是的,这个用户和这个令牌匹配,你现在可以从我们这里获取他们的一些数据。”
不过,从根本上说,OAuth 2.0 只是一个令牌协议。它具有与其他令牌协议相同的属性 - 您仍然需要 SSL 来保护这些令牌 - 它只是改变了这些令牌的生成方式。
OAuth 2.0 可以通过两种方式帮助您:
- 向其他人提供身份验证/信息
- 从其他人那里获取身份验证/信息
但归根结底,你只是……使用令牌。
回到你的问题
所以,您要问的问题是“我应该将我的令牌存储在 cookie 中并让我的环境的自动会话管理处理细节,还是应该将我的令牌存储在 Javascript 中并自己处理这些细节?”
答案是:做任何让你开心的事。
不过,关于自动会话管理的事情是,在幕后为您带来了很多神奇的事情。通常,自己控制这些细节会更好。
我 21 岁,所以 SSL 是的
另一个答案是:对任何事情都使用 https,否则盗贼会窃取您用户的密码和令牌。