——进一步探讨基于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 tokenvar profile = jwt.verify(req.body.token, secret);// if more than 14 days old, force loginif (profile.original_iat - new Date() > 14) { // iat == issued atreturn res.send(401); // re-logging
  }// check if the user still exists or if authorization hasn't been revokedif (!valid) return res.send(401); // re-logging// issue a new tokenvar 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/barAuthorization: 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 dbfunction(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 profilevar encrypted = { token: encryptAesSha256('shhhh', JSON.stringify(profile)) };// sing the tokenvar 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),喜欢灌水和闲聊的勿入~

转载于:https://www.cnblogs.com/foam/p/4770613.html

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

  1. 大规模运行MongoDB应该知道的10件事

    MongoDB的首席解决方案架构师Asya Kamsky 最近发表了一篇文章,概括了大规模运行MongoDB需要知道的10件事. MongoDB也需要DevOps.MongoDB是一个数据库.和任何其 ...

  2. 女孩做妻子前应知道的10件事

    女孩做妻子前应知道的10件事 一段时间的甜蜜恋爱期过后,你和心爱的他终于要踏上期盼已久的红地毯.你发誓一定要做个最幸福的小女人,要成一个永远让丈夫着迷的好妻子.从一个女孩的身份转变为一个妻子的身份前, ...

  3. 学习Go之前你应该知道的10件事 | Gopher Daily (2021.04.21) ʕ◔ϖ◔ʔ

    每日一谚:Don't use an interface if it's not clear how the interface makes the code better. Go技术生态 编写好的单元 ...

  4. 量子计算和人工智能:应该知道的10件事

    来源:中国机器人网 近年来,新兴技术变得突出.其中,量子计算具有改变我们世界的独特潜力.量子计算已经显示出有希望的证据,以令人难以置信的方式加速启发式计算.因此,在复杂的解决方案中应用量子计算来解决药 ...

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

    目前的市场上充斥着很多关于微软Office 365的炒作,相信厂商.客户或者企业的都有自己不同的考虑.Office 365是微软云版本的Office,用户可以通过互联网创建一个帐户,付款.下载应用安装 ...

  6. 每个程序员都应该知道的10件事!

    如果你已经编程了一段时间,并且想学习编程,那么你可能在想什么才是一个好的程序员?计算机科学与技术专业毕业生能做些什么,来为软件开发职业生涯做准备? 在本文中,我将分享10件我认为每个程序员都应该知道的 ...

  7. 关于Docker你应该知道的10件事

    如果你在企业IT工作,那你会听说过 Docker.即使在是像 Puppet.Hadoop 和 MongoDB 这样的热门技术中,Docker 也会脱颖而出.但正是因为 Docker 正处于炒作期,因此 ...

  8. 在IT界取得成功应该知道的10件事(ZT)

    1. 厚脸皮 - Thick skin 让我们面对现实吧.从各个方面来说,IT业从业人员很难受到欢迎.昨天有人坚持让你完成一项工作,如果你不好好干的话,你将会马上丢掉工作,因为客户的数据文件无法修复. ...

  9. 关于微软Silverlight,你应该知道的10件事

    对于任何成长中的企业来说,设计一个合适的网站是一件非常重要的事情,但是如何让你的网站具有富互联网应用程序(Rich Internet Applications,RIA)的体验却不是那么简单.为了在这方 ...

最新文章

  1. 如何在MySQL中进行FULL OUTER JOIN?
  2. mysql系统云结构图_腾讯梁定安解密织云系统!(附架构图)
  3. 信息系统项目管理师-项目成熟度模型、量化项目管理核心知识点思维脑图
  4. java 学习知识汇总
  5. java rsa 117_java实现RSA非对称加密解密
  6. 可能拥有海洋的天然卫星 科学家近日发现有食盐成分
  7. ARMLinux 下驱动开发第三节
  8. Mysql表引擎的切换
  9. 什么叫侧面指纹识别_屏幕指纹技术最强的3款全面屏手机,指纹识别技术手机你喜欢吗?...
  10. 让dataGridView中的复选框选中(winform)
  11. 什么是3D打印?游戏建模具体怎么做?哪个更有发展
  12. 利用Bitvise SSH Client与proxifier实现SSH全局代理
  13. Python课第3周:平方根格式化
  14. 手动查毒删除病毒文件图
  15. 【高等数学】区间再现公式及其相关推论
  16. UnityShader(四)基础光照
  17. 如何快速学习flex
  18. Python-求一元二次方程ax^2+bx+c=0的解
  19. [C++][linux]C++实现类似C#AutoResetEvent或者win C++的SetEvent
  20. gmod找不到好友服务器,Garry’s Mod|Gmod服务器架设教程(二)架设沙盒模式服务器...

热门文章

  1. cmd 修改mysql 密码_mysql怎么通过cmd更改密码?
  2. 2023产生的那些让我印象深刻的五个bug,无法释怀!
  3. 丁苯橡胶价格跌势有所放缓
  4. C++面向对象的三大特性
  5. 首届百度商业AI技术创新大赛重磅启动,以前沿科技革新生产力
  6. 手把手教你 3 分钟搞定个人网站 http 免费升级到 https
  7. 单片机汇编语言程序学习
  8. 2008年7月1日北京解禁柴油车
  9. 微信小程序|使用小程序制作一个世界杯球员识别工具
  10. Mysql、通信认证机制<前端学习笔记>