Day18-Session 管理(二)

前言

昨天讲了在产生 session ID 时有什麽应该要注意的地方,但除了 session 之外,现在也很流行用 JSON Web Token(JWT)做认证授权,所以今天要来说一说关於 JWT 的安全知识

JSON Web Token

用过 JWT 的人虽多,但可能不是每个人都熟悉他的原理,所以这边简单介绍一下,通常一个 JWT 会长得像下面这一大串,仔细看他其实可以根据 . 分隔三个部分,前两部分分别是 Header 跟 Payload,Header 里面通常会写他是用什麽演算法进行签章,让这个 JWT 不会被伪造,而 Payload 则是放这个 token 想要储存在浏览器上的内容。

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySUQiOjEyMzQ1LCJleHAiOjE2Mzk1NDgxMjF9.TuDvzeiQagBS_aFOBgVHvTGSol4Cu8-NXHdJTaPRMJ4
       Header       |                  Payload                   |                 Signature

而且他们都是由 JSON 格式的资料经过 Base64 编码後出来的(为了方便传输),如果想看他们原本长什麽样子只要用 Base64 解码回去就好了,譬如这串 JWT 的 header 就是 {"alg":"HS256"} 代表他用的签章演算法是 HMAC 加上 SHA256(看不懂没关系XD,这很正常),而 payload 则是 {"userID":12345,"exp":1639548121}

因此当使用者带着这串 token 发请求给 API Server,Server 就会先根据 Signature 检查这串 token 有没有被修改过,没有的话就把 payload 解开来看看,如果里面有 userID,那就代表这个使用者已经登入,可以进行各种操作

JWT 里面可以放哪些东西

因为 JWT payload 里面的东西虽然不会被篡改(改了 signature 就不对了),但他还是可以在 client 端被解开看到的,所以只能在里面放一些被看到也没事的东西,譬如说 userID、username、email 之类的

如果你为了自己方便在里面放了一些敏感资料,譬如说使用者的住址、密码之类的,否则万一这串长长的 token 不小心泄漏出去了,只要用 base64 把它解开就可以得到使用者的密码

记得要设 expiration time

在上面的范例中,payload 被解开之後有一个 "exp": 1639548121 就是指这个 token 什麽时候会过期,而且因为 payload 不能被篡改,所以一旦 server 看到 token 已经过期了,那就会要求使用者重新登入

那为什麽 token 一定要有期限呢?让使用者一个 token 用一辈子难道不好吗?

因为 JWT 不像 session ID 会存在资料库里面,一旦发行出去之後就没有办法手动撤销(revoke),只能等他自己过期,所以如果给了使用者一个一辈子都不会过期的 token,而且好巧不巧的这个 token 被骇客偷了去去,那骇客一辈子都可以使用这个 token 来进行操作

所以比较好的方式是每个 token 都给短短的时间(譬如说 30 分钟),如果使用者送来的 token 刚过期不久那就换一个新的给他,避免他三不五时就要重新登入。但如果真的过期太久了,譬如说已经超过七天,那代表这个礼拜使用者都没有上线用你的网站,这时候就可以直接拒绝他,请他重新登入之後再发给他全新的 token 给他

JWT 究竟要放在哪里呢?

在 Facebook 上的技术讨论社团待久了,三不五时就会看到有人在问 JWT 到底该放在哪里,是 localStorage、sessionStorage 还是 cookie?因为 JWT 就代表使用者的身份,而且有了这个 token 之後就可以用它来做任何事,所以应该要放在最安全的地方,也不能让不需要他的人可以碰到他

有了目标之後,我来们一一检视这三个选项:首先是 localStorage,放在里面的东西不只不会不见,而且任何第三方的脚本如 jquery、bootstrap 都可以取得里面的东西(但他们明明就不需要),所以显然 localStorage 不是一个很好的选项;而 sessionStorage 的话虽然每次浏览器关闭後都会清掉,但其实对於安全性没有太大帮助,因为第三方脚本还是可以拿到里面的东西,而且每次重开浏览器就要重新登入对使用者来说应该非常困扰

而 cookie 的话刚好非常符合需求,因为我们可以为他加上 HttpOnly 跟 Secure 属性,如此一来 JWT 就不会被第三方脚本偷走、就算中了 XSS 也没关系,而且传输的过程中也不会被中间人偷走,如果不嫌麻烦的话再加上 SameSite 又可以防 CSRF 攻击,可以说是非常好的解决方案。

所以如果哪天又有人问你 JWT 要放哪里才好时,不用犹豫,直接告诉他放在 cookie 加上 HttpOnly 跟 Secure 属性,才能保护好你的 JWT 喔

小结

JWT 作为近几年来新兴的认证授权解决方案,除了不用像 Session ID 存进资料库之外,也更适合分散式应用。但记得在使用 JWT 时不要忘记这些注意事项,才可以让你的网站既安全又方便哦~

关於今天的内容有什麽问题欢迎在下方留言,没问题的话我们就明天见罗~


<<:  [Day18] Operations Suite

>>:  day18 kotlin - flow基本操作

GitHub Self-hosted runners - 自订代理程序环境的最佳选项

Self-hosted runners 介绍 在前面几篇文章实作 GitHub Action Wor...

Android学习笔记01

MVVM 最近刚开始接触kotlin,而我想要用kotlin去建构一个MVVM的架构,首先要先了解甚...

Day29 Lab 2 - Object storage数据压缩

资料的压缩最好是能做在前端,因为网路最慢的地方就是前後端的沟通了,现在的压缩演算法有很多,举凡gzi...

DAY 5 html 基础网页

在昨天将 index 成功推上 Github 後,今天该让他有点东西了。 打开 VSCODE 後 按...

Day 29 : 整理篇 — 统整 Obsidian 的使用流程,建构一个完整的笔记系统

辛苦写到这里,一套完整的 Obsidian 笔记系统已经建构完成,接下来我使用下方的流程图帮大家做个...