这个问题在这里已经得到了解决,稍微有些不同的形式:
RESTful Authentication
但是这只涉及到服务器端。让我们从客户端的角度来看看这个问题。不过,在此之前,有一个重要的前提条件:
Javascript Crypto is Hopeless
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代码,你的浏览器加密仍然可能失败。
这使得许多RESTful身份验证方案在使用JavaScript客户端时变得不可能或愚蠢。让我们看看!
HTTP基本认证
首先是HTTP基本认证。最简单的方案:只需在每个请求中传递名称和密码即可。
当然,这绝对需要 SSL,因为您正在通过每个请求传递一个 Base64(可逆)编码的用户名和密码。任何监听线路的人都可以轻松提取用户名和密码。大多数“Basic Auth 不安全”的论点来自于“HTTP 上的 Basic Auth”,这是一个可怕的想法。
浏览器提供了内置的 HTTP Basic Auth 支持,但它非常丑陋,您可能不应该在应用程序中使用它。另一种选择是将用户名和密码存储在 JavaScript 中。
这是最符合 RESTful 的解决方案。服务器不需要任何状态知识,并验证与用户的每个交互。一些 REST 爱好者(主要是稻草人)坚持认为,维护任何形式的状态是异端邪说,如果您考虑任何其他身份验证方法,他们会口吐白沫。这种符合标准的理论优势是有的 - 它被 Apache 支持,您可以将对象存储为由 .htaccess 文件保护的文件夹中的文件,如果您的心愿意!
问题?您在客户端缓存用户名和密码。这使得恶意网站更容易破解 - 即使最基本的XSS漏洞也可能导致客户端将其用户名和密码发送到恶意服务器。您可以尝试通过哈希和加盐密码来减轻此风险,但请记住:
JavaScript Crypto是无望的。您可以通过将其留给浏览器的基本身份验证支持来减轻此风险,但......如前所述,丑陋。
HTTP摘要认证
jQuery是否支持摘要认证?
一种更“安全”的身份验证方式,它是一个请求/响应哈希挑战。但是JavaScript Crypto是无望的,因此它仅适用于SSL,并且您仍然必须在客户端上缓存用户名和密码,使其比HTTP基本身份验证更复杂但不更安全。
使用附加签名参数进行查询身份验证。
另一种更“安全”的身份验证方式是使用nonce和时间数据加密参数(以防止重复和定时攻击),然后发送它们。其中最好的例子是OAuth 1.0协议,据我所知,这是在REST服务器上实现身份验证的一种非常出色的方法。
https://www.rfc-editor.org/rfc/rfc5849
哦,但是 JavaScript 没有任何 OAuth 1.0 的客户端。为什么?
JavaScript 加密是无望的,请记住。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/
攻击者无法获得用户的凭据,但他们仍然可以冒充您的用户,这可能非常糟糕。
简而言之:通过未加密的方式发送令牌意味着攻击者可以轻松地抓取这些令牌并冒充您的用户。FireSheep是一个使这变得非常容易的程序。
一个单独、更安全的区域
您运行的应用程序越大,就越难以绝对确保它们无法注入一些代码来更改您处理敏感数据的方式。您绝对信任您的CDN吗?您的广告商?您自己的代码库?
常见的信用卡详细信息,不太常见的用户名和密码 - 一些实施者将“敏感数据输入”保留在与其应用程序其他部分不同的页面上,这个页面可以被严密控制和封锁,最好是难以钓鱼用户的页面。
Cookie(只是令牌的意思)
在cookie中放置身份验证令牌是可能的(也很常见)。这不会改变令牌身份验证的任何属性,它更多的是方便性问题。所有先前的论点仍然适用。
会话(仍然只是令牌的意思)
会话认证只是令牌认证,但有一些不同之处,使它看起来像是稍微不同的东西:
- 用户从未经身份验证的令牌开始。
- 后端维护一个与用户令牌相关联的“状态”对象。
- 令牌提供在cookie中。
- 应用程序环境为您抽象了细节。
除此之外,它与令牌身份验证没有什么区别。
这甚至偏离了RESTful实现的更远 - 随着状态对象,您正在走向基于有状态服务器的普通RPC的道路。
OAuth 2.0
OAuth 2.0解决了“软件A如何让软件B访问用户X的数据,而无需让软件B访问用户X的登录凭据”的问题。实现方式基本上只是用户获取令牌的标准方式,然后第三方服务会确认“是的,这个用户和这个令牌匹配,现在你可以从我们这里获取他们的一些数据”。但从根本上说,OAuth 2.0只是一个令牌协议。它具有其他令牌协议的相同属性-您仍然需要SSL来保护这些令牌-它只是改变了生成这些令牌的方式。OAuth 2.0有两种帮助您的方式:向他人提供身份验证/信息和从他人那里获取身份验证/信息。但归根结底,您只是使用令牌。回到您的问题,所以您要问的问题是“我应该将我的令牌存储在cookie中,并让我的环境自动会话管理处理细节,还是将我的令牌存储在Javascript中并自行处理这些细节?”答案是:“做让您开心的事情”。
自动会话管理的问题在于,背后有很多神奇的事情正在为您发生。通常最好掌控这些细节。
我已经21岁了,所以SSL是可以使用的
另一个答案是:对所有内容使用https,否则强盗将窃取您用户的密码和令牌。