一天 “小张” 接到一个需求 “一旦用户登陆认证成功之后,后续的请求可以携带一个令牌,无需再次身份认证”。
这时 “小张” 咨询了资深搬砖工程师 “小李”,凭借多年的搬砖经验,同事 “小李” 说到:HTTP 协议是无状态的,在第一次登陆认证成功后,下一次请求时,服务器也不知道请求者的身份信息。通常有两种实现方式:
“小张” 听完后,连忙说到第二种听着不错哦,搜索了一些相关文章介绍之后就开始了愉快的代码编写。完成之后提交了代码给同事 “小李” 做 code review,做为资深搬砖工程师的 “小李”,一眼看出了问题:“怎么能在 JWT 生成的 token 里放用户密码呢!JWT 默认是明文的,不能存储隐私信息”。
“小张” 不解,反问道:怎么会是明文呢,加密之后的数据我看了的,是一堆乱码啊,下面是打印的 token 信息。
// jwt 签名后生成的 token
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IuW8oOS4iSIsInBhc3N3b3JkIjoxMjM0NTYsImlhdCI6MTY2MTg2OTQxMX0.3-60HUf_cKIo44hWUviNzqdUoUGngGQfrqffg0A6uqM"
“小李” 通过一段 Node.js 代码展示了如何解密出 JWT 签名后的 token 数据。
此时的 “小张” 陷入了沉思,顿时心里产生了两个疑问????️:
带着这两个疑问,下一步让我们一块了解下 JWT 的原理。
JWT 全称 JSON Web Token,是一种基于 JSON 的数据对象,通过技术手段将数据对象签名为一个可以被验证和信任的令牌(Token)在客户端和服务端之间进行安全的传输。
JWT Token 由三部分组成:header(头信息)、payload(消息体)、signature(签名),之间用 . 链接,构成如下所示:
Header 部分由 JSON 对象 { typ, alg } 两部分构成,使用 base64url(header) 算法转为字符串:
Payload 部分为消息体,用来存储需要传输的数据,同样也是一个 JSON 对象使用base64url(payload) 算法转为字符串,JWT 提供了 7 个可选字段供选择,也可以自定义字段:
Signature 是对 Header、Payload 两部分数据按照指定的算法做了一个签名,防止数据被篡改。需要指定一个 sceret,产生签名的公式如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
生成签名后,将 header.payload.signature 三部分链接在一起,形成一个令牌(token)返回给客户端。
这就是 JWT 的原理,了解之后并没有那么神秘,回答上面的几个问题。
签名时使用了 secret,为什么是明文?
header、payload 部分是使用 base64 算法进行的编码,并没有被加密,自然也可以被解码。但注意这里的 base64 算法有点不一样的地方在于,token 可能会被放在 url query 中传输,URL 里面有三个特殊字符会被替换。下面是 JWT 中 base64url 的实现方式:
// https://github1s.com/auth0/node-jws/blob/HEAD/lib/sign-stream.js#L9-L16
function base64url(string, encoding) {
return Buffer
.from(string, encoding)
.toString('base64')
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
还需要注意 payload 对象放置的内容越多,base64 之后的字符串就越大,同理签名后的 token 也一样。
数据会不会被篡改?
数据一旦被篡改,到服务端也会认证失败的,服务端在生成签名时有一个重要的参数是 secret,只要保证这个密钥不被泄漏,就没问题,就算篡改也是无效的。
在 Node.js 中使用 JWT 需要用到 jsonwebtoken 这个库,API 很简单,主要用到两个方法:
const crypto = require('node:crypto');
const jwt = require('jsonwebtoken');
const secret = crypto.createHmac('sha256', 'abcdefg')
.update('')
.digest('hex');
const payload = {
"username": "张三",
"password": 123456,
iat: 1516239022
};
const token = jwt.sign(payload, secret)
const result = jwt.verify(token, secret)
JWT 由服务端生成可以存储在客户端,对服务端来说是无状态的,可扩展性好。
上文我们也讲了 JWT 中传输数据的 payload 默认是使用 base64 算法进行的编码,看似一串乱码,实则是没有加密,因此不要将涉及到安全、用户隐私的数据存放在 payload 中,如果要存放也请先自己进行加密。
一旦 token 泄漏,任何人都可以使用,为了减少 token 被盗用,尽可能的使用 HTTPS 协议传输,token 的过期时间也要设置的尽可能短。
防止数据被篡改,服务端密钥(secret)很重要,一定要保管好。
分享标题:Web安全-同事告诉我JWT是明文的...
分享链接:http://www.shufengxianlan.com/qtweb/news24/369574.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联