关于身份认证
传统的session认证
我们知晓,http协议本身是一种无状态的协议,用户对站点的每次访问,都需要提供凭证(账号密码)。站点需要一个标识来识别用户,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递到浏览器,通知它保存为cookie
会话,对应到我们服务器的信息,以便下次请求时核验,这就是传统的基于session
认证。
在站点运营日积月累下,基于session认证的问题逐渐暴露。每次记录的session随着用户增多,对应的消耗(IO/内存)增加,服务器的开销明显增大;依赖cookie的机制,使得cookie被截获后容易收到跨站请求
伪造的攻击(CSRF);扩展上难度较大,认证的方式在分布式场景不利于同步
基于token的鉴权机制
很多对外开放的API需要识别请求者的身份,并据此判断所请求的资源是否可以返回给请求者。token就是一种用于身份验证的机制,基于这种机制,应用不需要在服务端保留用户的认证信息或者会话信息,可实现无状态、分布式的Web应用授权,为应用的扩展提供了便利。
Json Web Token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准
RFC7519
。JWT一般可以用作独立的身份验证令牌,可以包含用户标识、用户角色和权限等信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,特别适用于分布式站点的登录场景。
JWT的构成
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
如上面的例子所示,JWT就是一个字符串,由三部分构成:
Header(头部)承载两个信息
- 声明类型(这里是JWT)
- 声明加密的算法
// 完整的头部如下 { 'typ': 'JWT', 'alg': 'HS256' }
头部信息会进行Base64编码,这是第一部分
- Payload(数据)
就是存放关键信息的地方。定义细节如下:
iss:令牌颁发者。表示该令牌由谁创建,该声明是一个字符串
sub:Subject Identifier,iss提供的终端用户的标识,在iss范围内唯一,最长为255个ASCII个字符,区分大小写
aud:Audience(s),令牌的受众,分大小写的字符串数组
exp:Expiration time,令牌的过期时间戳。超过此时间的token会作废, 该声明是一个整数,是1970年1月1日以来的秒数
iat: 令牌的颁发时间,该声明是一个整数,是1970年1月1日以来的秒数
jti: 令牌的唯一标识,该声明的值在令牌颁发者创建的每一个令牌中都是唯一的,为了防止冲突,它通常是一个密码学随机值。这个值相当于向结构化令牌中加入了一个攻击者无法获得的随机熵组件,有利于防止令牌猜测攻击和重放攻击。
另外,也可以新增用户系统需要使用的自定义字段,比如下面的例子添加了name(用户昵称)
{
"sub": "1234567890",
"name": "John Doe"
}
然后将其进行Base64编码,得到Jwt的第二部分:
- Signature(签名)
这个部分需要Base64编码后的Header和Base64编码后的Payload使用 '.' 连接组成的字符串,然后通过Header中声明的加密方式进行加密($secret 表示用户的私钥),然后就构成了jwt的第三部分。
// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '$secret');
将这三部分用 . 连接成一个完整的字符串,就构成了xxx.yyy.zzz的JWT。
特性和建议
- 默认不加密,不能将秘密数据写入
JWT
。 JWT
最大缺点是,由于服务器不保存session
状态,因此无法在使用过程中因业务变动废止某个token
,或更改token
的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。JWT
本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT
的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。- 为了减少盗用,
JWT
不应该使用HTTP
协议明码传输,要使用HTTPS
协议传输。
参考资料
jwt.io Debugger - 解码、验证和生成 JWT
本文由 ben 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 16, 2022 at 10:32 am