令牌身份验证和使用 cookie 进行身份验证有什么区别?
我正在尝试实施 Ember Auth Rails Demo,但我不明白使用令牌身份验证背后的原因,如问题“为什么使用令牌身份验证?”的 Ember Auth FAQ 中所述。
HTTP 是无状态的。为了授权您,您必须“签署”您发送到服务器的每个请求。
令牌认证
对服务器的请求由“令牌”签名 - 通常这意味着设置特定的 HTTP 标头,但是,它们可以在 HTTP 请求的任何部分(POST 正文等)中发送
优点:
您只能授权您希望授权的请求。 (Cookies - 甚至为每个请求发送授权 cookie。)
对 XSRF 免疫(XSRF 的简短示例 - 我会在电子邮件中向您发送一个看起来像 的链接,如果您已登录通过 cookie 对 bank.example 进行身份验证,而 bank.example 没有任何 XSRF 保护手段,我将从您的帐户中提取资金,因为您的浏览器将触发对该 url 的授权 GET 请求。)注意您可以使用基于 cookie 的身份验证来执行防伪措施 - 但您必须实施这些措施。
Cookie 绑定到单个域。在域 foo.example 上创建的 cookie 无法被域 bar.example 读取,而您可以将令牌发送到您喜欢的任何域。这对于使用多个需要授权的服务的单页应用程序特别有用——因此我可以在域 myapp.example 上有一个 Web 应用程序,它可以向 myservice1.example 和 myservice2.example 发出授权的客户端请求。
缺点:您必须将令牌存储在某处;而 cookie 是“开箱即用”存储的。想到的位置是 localStorage (con:即使关闭浏览器窗口后令牌也会保留), sessionStorage (pro:关闭浏览器窗口后令牌会被丢弃,con:在新选项卡中打开链接将呈现该选项卡匿名)和 cookie(Pro:关闭浏览器窗口后令牌会被丢弃。如果您使用会话 cookie,您将在新选项卡中打开链接时进行身份验证,并且您对 XSRF 免疫,因为您忽略了用于身份验证的 cookie,您只是将其用作令牌存储。缺点:每个请求都会发送 cookie。如果此 cookie 未标记为仅 https,则您对中间人攻击持开放态度。)
您必须将令牌存储在某处;而 cookie 是“开箱即用”存储的。想到的位置是 localStorage (con:即使关闭浏览器窗口后令牌也会保留), sessionStorage (pro:关闭浏览器窗口后令牌会被丢弃,con:在新选项卡中打开链接将呈现该选项卡匿名)和 cookie(Pro:关闭浏览器窗口后令牌会被丢弃。如果您使用会话 cookie,您将在新选项卡中打开链接时进行身份验证,并且您对 XSRF 免疫,因为您忽略了用于身份验证的 cookie,您只是将其用作令牌存储。缺点:每个请求都会发送 cookie。如果此 cookie 未标记为仅 https,则您对中间人攻击持开放态度。)
对基于令牌的身份验证进行 XSS 攻击稍微容易一些(即,如果我能够在您的站点上运行注入脚本,我可以窃取您的令牌;但是,基于 cookie 的身份验证也不是灵丹妙药 - 而 cookie 标记为http-only 不能被客户端读取,客户端仍然可以代表您发出请求,这些请求将自动包含授权 cookie。)
下载文件的请求应该只对授权用户有效,需要您使用 File API。对于基于 cookie 的身份验证,相同的请求开箱即用。
Cookie 身份验证
对服务器的请求始终由授权 cookie 登录。
优点:Cookie 可以标记为“仅限 http”,这使得它们无法在客户端读取。这更适合 XSS 攻击保护。开箱即用 - 您不必在客户端实现任何代码。
Cookie 可以标记为“仅限 http”,这使得它们无法在客户端读取。这更适合 XSS 攻击保护。
开箱即用 - 您不必在客户端实现任何代码。
缺点:绑定到单个域。 (因此,如果您有一个向多个服务发出请求的单页应用程序,您最终可能会做一些疯狂的事情,例如反向代理。) 易受 XSRF 攻击。您必须实施额外的措施来保护您的站点免受跨站点请求伪造。为每个请求发送出去,(即使是不需要身份验证的请求)。
绑定到单个域。 (因此,如果您有一个向多个服务发出请求的单页应用程序,您最终可能会做一些疯狂的事情,例如反向代理。)
易受 XSRF 攻击。您必须实施额外的措施来保护您的站点免受跨站点请求伪造。
为每个请求发送出去,(即使是不需要身份验证的请求)。
总的来说,我会说令牌给你更好的灵活性,(因为你没有绑定到单个域)。缺点是你必须自己做一些编码。
对于 Google 员工:
不要将状态性与状态转移机制混为一谈
状态
Stateful = 在服务器端保存授权信息,这是传统方式
无状态 = 在客户端保存授权信息,以及确保完整性的签名
机制
Cookie = 由浏览器进行特殊处理(访问、存储、到期、安全、自动传输)的特殊标头
Custom Headers = 例如授权,只是没有任何特殊处理的标题,客户端必须管理传输的各个方面
其他。可以使用其他传输机制,例如查询字符串是传输身份验证 ID 一段时间的选择,但由于不安全而被放弃
状态比较
“有状态授权”是指服务器在服务器上存储和维护用户授权信息,使授权成为应用程序状态的一部分
这意味着客户端只需要保留一个“身份验证 ID”,服务器就可以从其数据库中读取身份验证详细信息
这意味着服务器保留一个活动身份验证池(已登录的用户),并将为每个请求查询此信息
“无状态授权”是指服务器不存储和维护用户授权信息,它根本不知道哪些用户登录了,依赖客户端产生授权信息
客户端将存储完整的身份验证信息,例如您是谁(用户 ID),可能还有权限、到期时间等,这不仅仅是身份验证 ID,因此它被赋予了一个新的名称令牌
显然客户端是不可信的,所以auth数据和哈希(数据+密钥)生成的签名一起存储,其中密钥只有服务器知道,因此可以验证令牌数据的完整性
请注意,令牌机制仅确保完整性,而不是机密性,客户端必须实现
这也意味着对于每个请求,客户端都必须提交一个完整的令牌,这会产生额外的带宽
机构比较
“Cookie”只是一个标头,但在浏览器上预加载了一些操作
cookie可由服务器设置,客户端自动保存,同域自动发送
Cookie 可以标记为 httpOnly 从而阻止客户端 JavaScript 访问
预加载的操作可能在浏览器以外的平台(例如移动设备)上不可用,这可能会导致额外的工作
“自定义标头”只是没有预加载操作的自定义标头
客户端负责接收、存储、保护、提交和更新每个请求的自定义标头部分,这可能有助于防止一些简单的恶意 URL 嵌入
总结
没有魔法,身份验证状态必须存储在某个地方,无论是在服务器还是客户端
您可以使用 cookie 或其他自定义标头实现有状态/无状态
当人们谈论这些事情时,他们的默认心态主要是:无状态 = 令牌 + 自定义标头,有状态 = auth ID + cookie;这些不是唯一可能的选择
它们各有利弊,但即使是加密令牌,您也不应该存储敏感信息
典型的网络应用程序大多是无状态,因为它具有请求/响应性质。 HTTP 协议是 无状态 协议的最佳示例。但是由于大多数 Web 应用程序需要 state,为了保持服务器和客户端之间的 state,使用 cookie 以便服务器可以在每个响应中将 cookie 发送回客户。这意味着来自客户端的下一个请求将包含此 cookie,因此将被服务器识别。通过这种方式,服务器可以与 stateless 客户端保持 会话,了解有关应用程序 state 的所有信息,但存储在服务器中。在这种情况下,客户端在任何时候都不会持有 state,而这不是 Ember.js 的工作方式。
在 Ember.js 中,情况有所不同。 Ember.js 让程序员的工作变得更轻松,因为它确实为您在客户端保存了状态,随时了解其状态,而无需向服务器发出请求以获取状态数据。
但是,在客户端中保持状态有时也会引入在无状态情况下根本不存在的并发问题。然而,Ember.js 也为您处理这些问题;尤其是 ember-data 是考虑到这一点而构建的。总之,Ember.js 是一个为有状态客户端设计的框架。
Ember.js 不像典型的无状态 Web 应用程序那样工作,其中会话、状态和相应的 cookie 几乎完全由服务器处理。 Ember.js 将其状态完全保存在 Javascript 中(在客户端的内存中,而不是像其他一些框架那样在 DOM 中)并且不需要服务器来管理会话。这导致 Ember.js 在许多情况下更加通用,例如当您的应用程序处于离线模式时。
显然,出于安全原因,它确实需要在每次发出请求时将某种令牌或唯一密钥发送到服务器以进行身份验证。这样,服务器可以查找发送令牌(最初由服务器发出)并在将响应发送回客户端之前验证它是否有效。
在我看来,使用身份验证令牌而不是 Ember Auth FAQ 中所述的 cookie 的主要原因主要是因为 Ember.js 框架的性质,也因为它更适合 有状态网络应用范式。因此,cookie 机制并不是构建 Ember.js 应用程序的最佳方法。
我希望我的回答能给你的问题更多的意义。
令牌需要存储在某个地方(本地/会话存储或 cookie)
令牌可以像 cookie 一样过期,但你有更多的控制权
本地/会话存储无法跨域工作,请使用标记 cookie
将在每个 CORS 请求上发送预检请求
当您需要流式传输某些内容时,请使用令牌获取签名请求
处理 XSS 比处理 XSRF 更容易
每次请求都会发送令牌,注意它的大小
如果您存储机密信息,请加密令牌
JSON Web 令牌可用于 OAuth
代币不是灵丹妙药,请仔细考虑您的授权用例
http://blog.auth0.com/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/
http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/
我相信这里有些混乱。基于 cookie 的身份验证与现在使用 HTML5 Web Storage 实现的身份验证之间的显着区别在于,浏览器构建为在向设置它们的域请求资源时发送 cookie 数据。如果不关闭 cookie,您将无法阻止这种情况。浏览器不会从 Web Storage 发送数据,除非页面中的代码发送数据。页面只能访问它们存储的数据,而不能访问其他页面存储的数据。
因此,担心他们的 cookie 数据可能被 Google 或 Facebook 使用的方式的用户可能会关闭 cookie。但是,他们没有理由关闭 Web Storage(直到广告商也想办法使用它)。
所以,这就是基于 cookie 和基于令牌的区别,后者使用 Web 存储。
基于令牌的身份验证是无状态的,服务器不需要在会话中存储用户信息。这提供了扩展应用程序的能力,而无需担心用户登录的位置。基于 cookie 的 Web 服务器框架具有亲和力,而基于令牌的情况则不是问题。因此,可以使用相同的令牌从域中获取安全资源,而不是我们登录的域,从而避免另一个 uid/pwd 身份验证。
非常好的文章在这里:
在...时使用令牌
需要联合。例如,您想使用一个提供者 (Token Dispensor) 作为令牌颁发者,然后使用您的 api 服务器作为令牌验证者。应用程序可以向 Token Dispensor 进行身份验证,接收令牌,然后将该令牌提供给您的 api 服务器以进行验证。 (同样适用于 Google 登录。或 Paypal。或 Salesforce.com。等)
需要异步。例如,您希望客户端发送请求,然后将该请求存储在某处,以便“稍后”由单独的系统执行。该单独的系统不会与客户端建立同步连接,也可能不会与中央令牌药房直接连接。异步处理系统可以读取 JWT 以确定工作项是否可以并且应该在以后完成。这在某种程度上与上面的联邦思想有关。不过在这里要小心:JWT 过期。如果持有工作项的队列在 JWT 的生命周期内没有得到处理,则声明不应再受信任。
需要 Cient 签名请求。在这里,客户端使用他的私钥对请求进行签名,服务器将使用客户端已经注册的公钥进行验证。
主要区别之一是 cookie 受同源策略的约束,而令牌则不受。这会产生各种下游效应。
由于 cookie 仅发送到特定主机或从特定主机发送,因此该主机必须承担验证用户的责任,并且用户必须使用该主机创建一个包含安全数据的帐户才能进行验证。
另一方面,代币是发行的,不受同源政策的约束。发行人实际上可以是任何人,由主机决定信任哪些发行人。像 Google 和 Facebook 这样的发行人通常很受信任,因此主机可以将验证用户的负担(包括存储所有用户安全数据)转移给另一方,并且用户可以将他们的个人数据整合到特定的发行人下,而不必记住一个他们与之交互的每个主机的一堆不同的密码。
这允许单点登录场景,从而减少用户体验中的整体摩擦。从理论上讲,随着专门的身份提供商出现来提供身份验证服务,而不是让每个 ma 和 pa 网站都建立自己的(可能是半生不熟的)身份验证系统,网络也变得更加安全。随着这些供应商的出现,为即使是非常基本的资源提供安全网络资源的成本也趋向于零。
因此,总体而言,令牌减少了与提供身份验证相关的摩擦和成本,并将安全网络各个方面的负担转移到能够更好地实施和维护安全系统的集中各方。
简而言之:
JWT vs Cookie Auth
| | Cookie | JWT |
| Stateless | No | Yes |
| Cross domain usage | No | Yes |
| Mobile ready | No | Yes |
| Performance | Low | High (no need in request to DB) |
| Add to request | Automatically | Manually (if not in cookie) |
Are send out for every single request
也会为每个请求发送令牌crazy stuff like a reverse proxy.
总的来说,答案很好,但我觉得这部分有点误导。在单个 URL 端点下反向代理 API 并不疯狂,有时需要(必须为 SPA 网站支持 IE9 客户端一次)。为您的 API 设置一个单独的端点非常适合分散负载,尤其是在 SPA 网站中,或者您的 API 被其他应用程序大量使用的场景中。将反向代理标记为“疯狂的东西”有点过分。