美文网首页
Json Web Token 个人见解

Json Web Token 个人见解

作者: marchtea | 来源:发表于2018-10-10 15:43 被阅读181次

jwt(Json Web token) 是一种用于不同组织之间交换数据的格式。既然名称中包含了Json,显而易见,其数据结构是以Json为基础进行搭建的。数据中包含了三个部分,headerpayload以及token。其中token可以使用私钥(HMAC算法),也可以基于公私钥的形式,通过对header及payload进行计算生成,从而达到校验header及payload数据合法性的作用。

使用场景:

  • 跨域认证。单点登录系统是最常见的jwt使用场景。用户在登录后,系统返回jwt的信息。后续的所有请求都会带上jwt的信息,从而认证该用户的信息。由于数据的请求可以通过header、cookies、参数等方式,使得跨域访问变得十分简单。
  • 跨域数据分享。通过使用公私钥的方法,客户端可以使用公钥对签发的数据进行校验,从而保证数据不被篡改。

结构

​ jwt包含了三个部分

  • header
  • payload
  • signature

从结构上来看,三个部分都为base64-URL编码后,使用.拼接后的数据:

​ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

​ eyJpc3MiOiJzdW1tZXJAdGVuY2VudCIsImFkbWluIjoiRmFsc2UiLCJleHAiOjE1MzkwNTMxODV9.

​ Tc8VyoGFihW_CBXnCIX6eHzbLo3WEQH-Sy65ohSWfqM

header

​ header包含了typalg两个部分:

{
  "alg": "HS256",  // 计算的方法
  "typ": "JWT"     // 都为JTW
}

payload

payload则包含了本次声明的数据。数据分为几个类型

  • jwt协议中定义的声明
    • iss 签发人
    • sub 主题
    • aud 受众
    • exp 过期时间
    • nbf 生效时间
    • jti jwt id
  • 通用的数据
  • 私有的数据: 用户自己定义的数据

一个payload的样例:

{
    "sub": "userinfo",
    "name": "testuser",
    "admin": false
}

signature

signature是对headerpayload的数据进行签名。签名的算法可以使用HMAC RSA256,也可以使用RSA256.前者需要所有的使用者都拥有加密的secret,后者的使用者则需要RSA的public key用于数据的解密。

signature的算法通常如下:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

使用

从上面的定义来看,jwt本身是十分简单的。而且各种语言的JSON Parser都很全,所以相应的库也十分全面,基本常见的语言都是支持的。而且一种语言都有非常多的轮子,具体可以参考

这里就简单的以python作为样例,使用的是pyjwt,文档请参考

HMAC

import jwt
key = 'secret'
encoded = jwt.encode({'sub': '123456', 'user': 'testuser'}, key, algorithm='HS256')
decoded = jwt.decode(encoded, key, algorithms='HS256')

RSA

RSA算法的用法和HMAC类似

import jwt
encoded = jwt.encode({'sub': 123456, 'user': 'testuser'}, pri, algorithm='RS256')
decoded = jwt.decode(encoded, pub)

交互

How does a JSON Web Token work

jwt适用的场景是跨域的数据认证。通常的使用流程如下:

  1. client需要访问服务资源,首先请求认证服务器,通过相应的参数,获取合法的jwt token
  2. client在后续所有的访问中,都在请求包带上jwt token
  3. 资源的服务器校验该jwttoken是否合法。由于jwt的特性,校验可以在服务器本地完成,而不需要去请求远端的认证服务器。

请求时,带参数的方式有多种:

  1. cookies

    如果认证服务器与资源服务器是同域的,则可以把jwt token放在cookies进行携带。

  2. header

    对于跨域的情况,则可以在请求的header中添加Authorization: bearer <token>字段的方式来传递。由于是在header中添加数据,所以没有跨域的cookies无法携带的问题。

  3. params

    还有就是在请求的参数中增加token字段。比如Get方法中的url&token=xxx的形式,或者是Post中的请求参数

tips

使用claim校验

jwt官方定义了几种常用的claim,用于对数据合法性进行校验.常用的有:

  • exp: token的过期时间。

    服务端或者客户端进行decode时,可以自动捕获超时错误。

    jwt.encode({'exp': datetime.utcnow()}, 'secret')
    try:
        jwt.decode('JWT_STRING', 'secret', algorithms=['HS256'])
    except jwt.ExpiredSignatureError:
        # Signature has expired
    
  • nbf: token的启用时间

  • iss: token的签发者

  • aud: token的接受者

stateful & unstateful

stateful和unstateful是由jwt中数据存储的内容决定的. 如果jwt中的数据包含了所需要的全部数据, 每个client在使用数据时, 不需要再到某个服务中进行合法性校验, 则这个jwt是unstateful的, 反之, 则是stateful的.

举个例子:

{
    "uid": 123456,
    "exp": 1539148957,
    "group": "admin",
    "company": "1"
}

上面这个jwt包含了uid, group, company字段. 这些数据已经足够处理后续的所有请求了. 因此, client在执行的时候, 不需要再请求一次服务器, 获取剩余的数据. 这种jwt, 可以称之为 unstateful的.

再看下面这个:

{
    "uid": "sess-1234-412-x12",
    "exp": 1539148957
}

这个jwt中仅仅包含了一个uid信息, 所有的数据都没有. 在使用时, 还需要再请求一个服务获取相应的数据, 这种jwt就是stateful的.

当然, stateful的jwt, 也可以包含所有的数据.

{
    "uid": 123456,
    "exp": 1539148957,
    "group": "admin",
    "company": "1",
    "tid": "123-xx-xx"
}

在使用该jwt之前, 需要首先校验该tid是否还是合法. 一般会在一个服务器中维护一个tid的黑名单. 如果该tid属于黑名单中, 则强制废除该jwt.

安全问题

虽然token看起来是一段加密后的数据, 而且还用了加密算法, 但实际上并不是加密的. 回顾下token的样子,

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

eyJzdWIiOjEyMzQ1NiwidXNlciI6InRlc3R1c2VyIn0.

NAHaQSXelvub7_y3XSXpofBQDuzBrGGxeJ4SAQPkYRE

token分成了三段:

  • header
  • payload
  • token

其中, header\payload都是仅仅用base64-URL encode后的结果. 也就是说,谁都可以做decode获取数据. 所以, jwt中一定不能包含涉密的数据,尤其是用户密码等敏感信息

性能问题

这里的性能问题, 指的是该结构带来的请求数据变多的问题. 在jwt的使用场景中, 所有的请求都需要完整带上jwt的数据. 由于payload这部分的数据仅仅是base64后的数据, 并没有做任何处理. 所以, 如果在payload中增加过多的数据, 就会导致jwt的结构变大, 从而导致请求的效率降低.

替代session

jwt的竞争对手并不是传统的session, 而是其他的跨域认证方案, 例如SAML以及SWT. 但是, 也有很多人使用jwt作为session的替代品进行使用. 选择jwt的原因大多数如下:

  • 平行扩容

    使用session的服务在用了jwt后, 完全可以在本地对jwt发过来的数据进行校验, 从而不需要传统的session记录. 因此, 当服务快速平行扩容时, 也不会因为session记录找不到而引起问题.

  • 免去session服务器

    同样的, 因为jwt已经记录了用户相关的信息, 也就不需要再去session获取一次用户的数据. 从而避免session服务器成为卡点.

当然, 这两点优势也饱受质疑.

首先, 现在session大多都直接存放在redis, memcache等缓存中, 已经没有什么人使用本地的文件存储了. 此外, 也可以通过负载均衡来保证访问都单用户请求都落在单一服务器上.

而对于免去session服务器, 则要看如何定义jwt中的数据. 前面说过, jwt可以是unstateful或者是stateful的. 对于unstateful的jwt, 当登录服务器签发了之后, 该jwt只要在exp之前都长期有效. 所以服务端是无法知道当前有多少用户在线. 这对于某些应用是不合适的. 而且, 废除jwt也成为了件难事. 如果需要废除已经签发, 但仍在有效期的jwt, 就需要添加一个黑名单, 那就变成了stateful的jwt, 而且也需要一个集中化的服务.

结论

jwt在2015年就已经成为RFC标准, 其token生成的设计, 很好的解决了不同组织之间相互数据信任的问题, 因而在单点认证方面得到了大规模的应用.

在单体服务中, jwt也被很多人用来作为session的替代品进行使用, 也引来了很多的讨论, 甚至是互喷. 整体上来说, 经过设计, 对于某些场景下, 由于签发的数据天然就带了可信任的token, 所以不需要再进行远端校验, 确实是能提高系统整体的吞吐率.

相关文章

  • JSON Web Token

    JSON Web Token (JWT)是一种基于 token 的认证方案。 JSON Web Token 的结构...

  • JSON Web Token

    What is JSON Web Token? JSON Web Token (JWT)是一个开放标准(RFC 7...

  • Json Web Token 个人见解

    jwt(Json Web token) 是一种用于不同组织之间交换数据的格式。既然名称中包含了Json,显而易见,...

  • OAuth2和JWT学习资源记录

    八幅漫画理解使用JSON Web Token设计单点登录系统JSON Web Token - 在Web应用间安全地...

  • JWT 概述与代码实现

    一、什么是JSON Web Token? JSON Web Token(JWT)是一个开放标准(RFC7519),...

  • golang之JWT

    什么是JSON Web Token? JSON Web Token(JWT)是一个开放标准(RFC 7519[ht...

  • JWT简介

    JSON Web Token (JWT) 参考资料:Introduction to JSON Web Tokens...

  • 认识JWT[转载]

    1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519...

  • 认识JWT(转)

    1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519...

  • 认识JWT

    1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519...

网友评论

      本文标题:Json Web Token 个人见解

      本文链接:https://www.haomeiwen.com/subject/fuopaftx.html