关于Tokens你需要知道的10件事

——进一步探讨基于Token认证的一些常见问题

原文链接:Here

原作者:Matias Woloski

几周前我们发表了一篇短文《cookies与tokens在单页应用中的对比》(主要以AngularJs应用为例)。社区里对这个话题很感兴趣,于是我们接着发表了第二篇《在socket.io等实时框架中基于Token的认证》。趁着大家对这个话题还保持着热情,我们决定再写一篇文章进一步探讨基于Token认证的常见问题。我们开始吧~

1.Tokens需要保存在Local Storage、Session Storage或Cookies中

在Tokens被应用于单页应用的背景下,有人提出了问题:在浏览器中刷新页面时,token会发生什么变化。答案很简单:你需要将token保存在Local Storage、Session Storage或客户端内置的Cookies中,在浏览器不支持Session Storage的情况下,它会被polyfills为cookies。

你或许想问“但如果我将token保存在cookie的话,岂不是很危险”。其实不然,这种情况下,你使用的cookies只是作为存储机制而非验证机制(即是说,web框架不会使用cookie来验证用户,因此不存在XSRF攻击的危险)

2.Tokens像Cookies一样会过期,但你有更多的控制权

Tokens具有生命周期(在JSON Web Tokens中由exp属性控制),否则用户就可以登录一次却永远无需认证了。Cookies由于相同的原因也具有生命周期。

在Cookies中,如下不同情况生命周期也不一样:

1.当关闭浏览器时,Cookies会被销毁(如Session Cookies)

2.你也可以实现一个服务端检查机制(通常由Web框架帮你完成),你可以设置生命周期或滑动窗口生命周期。

3.Cookies在一段时间内可以是永久的(即使关闭浏览器也不会被销毁)

在Tokens中,一旦过期,你只需要获取一个新的token。你可以写一个端点来更新token:

1.验证旧的token

2.检查用户是否还处于登录状态或者在访问你的网站

3.产生一个重新续时的新token

你甚至可以将token生成的时间写入其中,并在大约两周后强制用户重新登录。

app.post(‘/refresh_token‘, function (req, res) {
  // verify the existing token
  var profile = jwt.verify(req.body.token, secret);

  // if more than 14 days old, force login
  if (profile.original_iat - new Date() > 14) { // iat == issued at
    return res.send(401); // re-logging
  }

  // check if the user still exists or if authorization hasn‘t been revoked
  if (!valid) return res.send(401); // re-logging

  // issue a new token
  var refreshed_token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });
  res.json({ token: refreshed_token });
});

  

3.Local/Session Storage无法跨域,请使用Cookies作标记

如果你将cookie的作用域名设置为.yourdomain.com,那么它可以在yourdomain.comapp.yourdomain.com中被访问。如果用户在主域登录却被重定向到app.yourdomain.com,要验证cookie也是很方便的。

Tokens存储在local/session storage中,这意味着不同域名之间是无法相互访问的(即使是子域名)。那么你该怎么做呢?

其中一种做法是,当用户在app.yourdomain.com中验证完毕后,你生成一个token并设置一个作用域名为.yourdomain.com的Cookie标记用户已经登录。

$.post(‘/authenticate, function() {
  // store token on local/session storage or cookie
    ....

    // create a cookie signaling that user is logged in
  $.cookie(‘loggedin‘, profile.name, ‘.yourdomain.com‘);
});

然后,你可以在yourdomain.com验证cookie的存在并重定向到app.yourdomain.com。而Token可以在app的子域中使用(如果token依然合法)。

可能会出现cookie存在而token已经被删除的情况。这种情况下,用户必须重新登录。这里需要强调的是,正如我们之前所说,我们并不将cookie当作验证机制,而仅仅把它作为能够跨域保存信息的存储机制。

4.每个CORS请求都会先发一个预请求

有人指出,Authorization报头并非一个简单的报头,因此在向特定URLs发送请求前都需要发送一个预请求。

OPTIONS https://api.foo.com/bar
GET https://api.foo.com/bar
   Authorization: Bearer ....

OPTIONS https://api.foo.com/bar2
GET https://api.foo.com/bar2
   Authorization: Bearer ....

GET https://api.foo.com/bar
   Authorization: Bearer ....

这时你需要发送Content-Type: application/json

提醒下,OPTIONS请求自身并没有Authorization报头信息,所以你的web框架需要对OPTIONS和后续的请求作一些处理(提示:微软的IIS因为某些原因在这方面存在一些问题)。

5.当你处理流媒体时,请用token获取签名请求

在使用cookies时,你可以轻易地触发文件下载和一些文本流。然而,在tokens中,是通过XHR来完成请求的,你无法依赖于此。解决的办法就是像AWS那样生成一个签名请求,例如,Hawk Bewits就是一个支持该方法的优秀框架:

请求:

POST /download-file/123
Authorization: Bearer...

回应:

ticket=lahdoiasdhoiwdowijaksjdoaisdjoasidja

其中,ticket是无状态的。它通过URL: host + path + query + headers + timestamp + HMAC来生成,并带有过期时间。所以它能在一段时间内(比如5分钟)被用来下载文件。

你会被重定向到/download-file/123?ticket=lahdoiasdhoiwdowijaksjdoaisdjoasidja。服务器将验证ticket是否合法并完成接下来的业务操作。

6.比起XSRF,处理XSS较为容易

Cookies具有允许设置HttpOnly标记的特性,它可以只允许服务器访问而非JavaScript。这很有用,因为它保护Cookies不被客户端代码注入攻击(XSS)。

由于tokens被存储在local/Session Storage或者客户端内置的Cookie中,这容易遭受XSS攻击并被攻击者获取到token。这是个令人担忧的问题,因此你需要将tokens的生存时间设置得短一点。

Cookies层面上,一种主要的攻击是XSRF。真实情况是,XSRF是最让人忽略的攻击之一。普通的开发者可能甚至不了解这种风险,因此很多应用缺少反XSRF攻击的机制。然而,每个人都知道注入是什么。简单地说,如果你允许在不转义的情况下渲染用户输入的内容,那么你的应用就暴露在XSS攻击之下了。根据我们的经验,防范XSS比XSRF容易。因为并非所有的web框架都内置了反XSRF机制,而在绝大多数支持转义语法的模板引擎中,防范XSS却是容易得多。

7.每次请求都需要发送token,请注意它的大小

当你每发送一次API请求,都需要将token附加到Authorization头部中发出去。

GET /foo
Authorization: Bearer ...2kb token...

和Cookies的比较

GET /foo
connect.sid: ...20 bytes cookie...

token的大小取决于你将多少信息存在里面了,这可能会很大。相比起来,Session Cookies只保存一个标记(connect.sid,PHPSESSID等等),主体内容被保存在服务端(仅有一台服务器就保存在内存,在服务器群中则保存在数据库)。

现在,你完全可以实现一个类似tokens的机制。这个token拥有你需要的基本信息,在服务端中根据每次API的调用,你都可以为token补充更多的信息。Cookies的确也能做到这样,但不同的是tokens有一个好处,你可以完全控制它,毕竟它是你代码的一部分。

GET /foo
Authorization: Bearer ……500 bytes token…

在服务端中:

app.use(‘/api‘,
  // validate token first
  expressJwt({secret: secret}),

  // enrich req.user with more data from db
  function(req, res, next) {
    req.user.extra_data = get_from_db();
    next();
  });

值得注意的是,你可以完整地将Session保存在Cookie中(而不仅仅是一个标记)。但并不是所有的Web平台都支持这么做,举个例子,在Node.js中,你可以使用mozilla/node-client-sessions

8.如果存储敏感信息,请对token加密

Token的签名能够防止信息被篡改,TLS/SSL能够防止中间人攻击。但如果包含了用户的敏感信息(身份证号等),你就需要对它进行加密。JWT(JSON Web Tokens)用JWE(JSON Web Encryption)作为规范,但大多数类库都还没有实现JWE,所以最简单的做法就是像下面那样使用AES-CBC模式进行加密。

app.post(‘/authenticate‘, function (req, res) {
  // validate user

  // encrypt profile
  var encrypted = { token: encryptAesSha256(‘shhhh‘, JSON.stringify(profile)) };

  // sing the token
  var token = jwt.sign(encrypted, secret, { expiresInMinutes: 60*5 });

  res.json({ token: token });
}

function encryptAesSha256 (password, textToEncrypt) {
  var cipher = crypto.createCipher(‘aes-256-cbc‘, password);
  var crypted = cipher.update(textToEncrypt, ‘utf8‘, ‘hex‘);
  crypted += cipher.final(‘hex‘);
  return crypted;
}

当然,你也可以像#7那样,将敏感信息保存在数据库中。

9.JSON Web Tokens可以在OAuth中使用

Tokens往往和OAuth联系在一起。OAuth2是一种解决身份认证授权的协议。经过用户同意授权访问自己的数据后,认证服务器会返回一个access_token,这样可以使用用户的身份访问对应的APIs。

通常这些tokens是不透明的。他们被称之为bearertokens,并且以随机字符串保存到某种类型的哈希表中,并存储在服务器里(数据库、缓存等)。内容包括过期时间、请求范围(例如访问好友列表)以及授权的用户。然后当API被调用时,token会被发送给服务器,服务器会在哈希表中查找信息并开始验证(比如token是否已过期,是否超出请求范围)。

这种token和我们一直讨论的签名token(如JWT)的主要区别是,后者是无状态的,它们并不需要存储在哈希表中,因此它是一种更轻量级的方法。OAuth2并没有规定access_token的格式,所以你可以返回一个经授权服务器包含的带有“请求范围、权限列表和过期时间”的JWT。

10.Tokens不是万能的,请仔细考虑授权使用场景

几年前,我们为一家大公司实施开发基于token的架构。这是一个有大量信息需要被保护的拥有超过10万名员工的公司。他们想要实现一个基于“身份验证和授权”的集中式管理组织系统。试想想“用户X可以读取W地区里Z医院的临床试验Y的ID和名称”的应用场景。这种细粒度的授权,你可以想像,不管是在技术还是管理上,都是很难处理的。

  • Tokens会变得很大
  • 你的apps/APIs会变得很复杂
  • 不管是让谁来授予权限都是很难进行下去的

站在信息架构的角度上,为确保创建合理的作用范围和权限,我们放弃了这个工作。

结论:要抵制把一切东西都转换成tokens的诱惑,在使用这种方式时请务必先做好各种分析。

本文固定链接: http://zoufeng.me/2015/08/12/ten-things-you-should-know-about-tokens-and-cookies

推荐一个php进阶开发群(467634807),喜欢灌水和闲聊的勿入~

时间: 2024-11-09 00:54:36

关于Tokens你需要知道的10件事的相关文章

使用Office 365前,企业必须要知道的10件事

目前的市场上充斥着很多关于微软Office 365的炒作,相信厂商.客户或者企业的都有自己不同的考虑.Office 365是微软云版本的Office,用户可以通过互联网创建一个帐户,付款.下载应用安装,然后使用,这一过程中不需要使用光盘.如果企业用户认为使用Office 365对于公司来说是正确的一步的话,那么管理者就有必要先了解以下由桌面解决方案顾问Sales Harkins所提出的10件事. 1.什么是云? 云是一个行业术语,指异地文件托管服务.当使用Office 365文件的时候,用户使用

摄影新手最想知道的10件事(转)

摄影新手最想知道的10件事 原文地址 http://www.fsbus.com/danfanrumen/25114.html 作为摄影新手 面对摄影难免有许多疑问 焦距.光圈.景深.快门如何把控? 怎么拍才不跑焦? 如何掌握构图.用光? 一天中最佳拍摄时间是什么时候? 无需上网逐个搜索这些问题 在本篇文章中小编为你整理了 摄影新手最想知道的10件事 简单易懂 赶紧马住 焦距镜头的焦距是什么呢?简单来说,就是一个镜头能拍多远或者多宽.数字越小,焦距越短,视角也就越广,反之,数字越大,焦距越长,视角

iOS 9:你需要知道的10件事

所有的iPhone用户都在翘首等待最新的iOS发布,iOS 9于昨日正式发布!在这里我们一起来看看有关于iOS 9你必须了解的10件事. 1) Notes 苹果公司的Note应用程序将变得更加先进,其将能够在你的日常生活中作出更大的贡献.新增类别标题.地图.图片,同时URL支持也加入其中.新版本的Note应用程序将为用户提供使用图像注释和创建手写提醒的功能. 2) 地图 用户们可以预计到苹果的地图将会彻底转变.最初,当苹果刚开始推出地图时出现了很多问题,它无法在其推出的初始阶段获得准确的数据.随

关于CSS需要知道的10件事

原文: http://dsheiko.com/weblog/10-things-to-need-to-know-about-css CSS may look as a simple language. In fact it can be simple only to use, but definitely not simple to maintain. CSS看起来是个简单的语言,实际上只是使用较为简单,但是很显然维护它并不简单. Observing that the maximum numbe

网站开发人员应该知道的61件事

    作者 Hoogle, 火龙果软件 发布于:2014-01-23   有人在Stack Overflow上发问,动手开发网站之前,需要知道哪些事情? 不出意料地,他得到了一大堆回答. 通常情况下,你需要把所有人的发言从头到尾读一遍.但是,Stack Overflow有一个很贴心的设计,它允许在问题下方开设一个wiki区,让所有人共同编辑一个最佳答案.于是,就有了下面这篇文章,一共总结出六个方面共计61条"网站开发须知". 我发现,这种概述性的问题,最适合这种集合群智.头脑风暴式的

[转载]网站开发人员应该知道的61件事

http://news.cnblogs.com/n/82363/ 网站开发人员应该知道的61件事 原文网址:http://stackoverflow.com/questions/72394 译者:阮一峰 一.界面和用户体验(Interface and User Experience) 1.1 知道各大浏览器执行Web标准的情况,保证你的站点在主要浏览器上都能正常运行.你至少要测试以下引擎:Gecko(用于Firefox).Webkit(用于Safari.Chrome和一些手机浏览器).IE(你可

在开发第一个Android应用之前需要知道的5件事:

你能否详细讲述一下,在开发Android应用过程中每一阶段要用到的技能和编程语言? 建立一个Android应用程序可以归结为两个主要技能/语言:Java和Android系统.Java是Android的通用编程语言,但是Android还包括学习用于app界面设计的XML语言,学习Android概念,以及从Java编程角度运用这些概念. 学了Java和XML之后,再用Android理念将两者连接起来. 我也有分享过一些学习Activities和 Fragments等的Android相关知识.我最喜欢

react.js 你应知道的9件事

React.js 初学者应该知道的 9 件事 本文假定你已经有了一下基本的概念.如果你不熟悉 component.props 或者 state 这些名词,你最好先去阅读下官方起步和手册.下面的代码示例我将使用 JSX 作演示,因为使用 JSX 语法写组件更为简洁,也更具表达力. 1. React.js 只是一个视图库 我们从最基本的开始.React 不是一个 MVC 框架,好吧,它根本就不是一个框架.它只是一个渲染视图的库.如果你对 MVC 熟悉的话,你就会意识到 React.js 只对应了V 

关于Java你可能不知道的10件事

关于Java你可能不知道的10件事 分享到: 24 本文由 ImportNew - Jerry Lee 翻译自 Jooq.欢迎加入翻译小组.转载请参见文章末尾的要求. 呃,你是不是写Java已经有些年头了?还依稀记得这些吧: 那些年,它还叫做Oak:那些年,OO还是个热门话题:那些年,C++同学们觉得Java是没有出路的:那些年,Applet还风头正劲-- 但我打赌下面的这些事中至少有一半你还不知道.这周我们来聊聊这些会让你有些惊讶的Java内部的那些事儿吧. 1. 其实没有受检异常(check