FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

[译]Introduction to JSON Web Tokens #170

Open FrankKai opened 4 years ago

FrankKai commented 4 years ago

https://jwt.io/introduction/

FrankKai commented 4 years ago

什么是JSON Web Token?

FrankKai commented 4 years ago

什么时候使用JSON Web tokens?

下面这些场景下,JSON Web Tokens是有用的:授权和信息转换。

授权

这是JWT最常用的场景。一旦用户登录进来,随后的请求都会带上JWT,允许用户获得token允许的routes,services和资源。SSO是现今广泛使用JWT的一个特性,因为其开销小,以及跨域名可以很容易实现。

信息转换

JWT是两个组织之间进行安全信息传输的很好的方式。因为JWT可以签名---例如,使用public/private键对,可以确定发送者就是他们说的那个人。除此之外,使用header和payload计算签名,可以验证内容是否被人篡改。

FrankKai commented 4 years ago

JSON Web Token结构是什么样的?

JWT的结构很简单,JSON Web Tokens由三部分组成,它们之间通过.连接。 三部分主要是:Header, Payload, Signature。 因此JWT的格式就像这样:xxxxx.yyyyy.zzzzz。 现在我们一点一点去拆分每一部分。

Header

header由两部分组成:token的类型,也就是JWT;token的签名算法,可以是HMAC,SHA256和RSA。 例如:

{
    "alg": "H256",
    "typ": "JWT",
}

编码是Base64Url格式的,作为JWT的第一部分。

Payload

token的第二部分是payload,其中包含了claims(声明)。 Claims指的是实体(典型的是user)和额外数据的语句。 有三种类型的claim:registered,public和private claim。

Registered claims

有一个预先定义好的claim集合,不是强制的但是非常推荐的,去提供有用的彼此协作的claim。其中包括,iss(issuer),exp(expiration time),sub(subject),aud(audience)和其他的。

注意:claim或者声明的名字只有3个字符长的原因,是因为JWT的目的是紧凑。

Public claims

这些可以由使用JWT的人随意定义。但是为了避免collision它们应该在IANA JSON Web Token Registry注册或者可以定义成一个URI,这个URI上包含了一个耐碰撞名称空间。

Private claims

这些是自定义的claim。两个组织之间约定好既不通过registered claim也不通过public claim,而是通过自定义的claim去分享信息。

一个payload示例如下:

{
    "sub": "1234567890",
    "name": "FrankKai",
    "admin": true
}

编码是Base64Url格式的,作为JWT的第二部分。 注意:对于签名token来说,尽管可以保护其不被篡改,但是对于所有人都是可读的。不要在payload或者JWT的header元素上存储secret information,除非是经过加密的。

Signature

为了创建编码头的signature部分,在header上需要指明编码后的payload,编码后的payload和一个secret,以及签名算法并且签名。

例如如果你想用HMAC SHA256算法,签名会按照下面的方式创建:

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

签名用于验证消息在整个过程中没有被更改,并且,对于使用私钥签名的令牌,它还可以验证JWT的发送方就是它所说的发送方。

Putting all together

输出是3个被.分离的Base64-URL字符串,可以在HTML和HTTP环境中传输,与基于XML的标准比如SAML相比,这种格式更简单。

下面的输出表示JWT的header和payload是编码过的,并且用一个secret做签名。

image

如果想体验一下JWT,可以用jwt.io Debugger去解码,验证以及生成JWT。

image

找一个自己公司的试试: image

我司由于最近才接入了单点,经验不是很成熟,所以jwt中包含了用户密码的敏感数据。

存储在localStorage中的jwt,payload中包含了用户密码,使用https://hashkiller.co.uk/Cracker/MD5 这个网站可以成功解析出。 image

在我的沟通下,服务端做了调整。 image

image

FrankKai commented 4 years ago

JSON Web Tokens是如何工作的?

在验证时,当用户成功使用凭证登录成功以后,一个JSON Web Token会返回。因为token是凭证,必须严加保管从而避免安全问题。总的来说,不需要时就不要留着token了。

处于缺乏安全性的考虑,不要在浏览器storage存储敏感的session数据。

如果用户什么时候想获取被保护的路由或者资源,用户代理需要发送JWT,典型的场景是在Authorization header上使用Bearer字段。header的内容看起来像下面这样:

Authorization: Bearer <token>

这是一个无状态的验证机制。服务端的保护路由会在Authorization header上检查这个有效的JWT,而且如果存在的话,用户会被赋权去获得被保护的资源。如果JWT包含了必要的数据的话,为了特殊操作查询数据库的需要也许会被减少。

如果token放在Authorization header上的话,CORS没有问题,因为没有用cookie。

下面这个流程图展示了JWT是如何生成和如何从API获取资源的: image

1.应用或者client向鉴权服务器请求鉴权。这是通过不同的授权流之一执行的。例如,一个OpenID Connect web应用会到/oauth/authorize端点使用authorization code flow。 2.当权被分配时,鉴权服务器返回一个权限token给应用。 3.应用会用access token去获取被保护的资源。(比如一个API)

注意signed tokens,在token上包含的所有信息会暴露给用户和其他组织,即使他们不能改变它。也就是说你不要在token上传递敏感信息。

备注:我们公司的内部管理系统,在jwt的payload上添加了用户密码,这样很不安全。服务端给出的处理是jwt的payload上移除用户密码;md5加密增加salt。

FrankKai commented 4 years ago

我们为什么要使用JSON Web Tokens?

Simple Web Tokens(SWT)和 Security Assertion Markup Language Tokens(SAML)也是两种token方式,我们来讨论下JSON Web Tokens(JWT)的好处。

JSON比XML更简洁,它编码以后会更小,JWT比SAML更简洁。这使得JWT成为一种HTML和HTTP环境下的很好的传输选择。

SWT可以通过HMAC算法用共享密码做对称签名。然而,JWT和SAML token用公共/私密X.509键值对格式。在和签名JSON做对比时,没有引入模糊的安全漏洞的对XML做XML数字签名是非常困难的。

JSON parsers在大多数程序语言中都是可用的,因为它们直接映射成objects。相反地,XML没有自然文档-对象映射。所以用JWT比SAML更好。

JWT在互联网上广泛应用。所以再多个平台尤其是移动端上处理JWT是非常方便的。

JWT比SAML又短又清晰

image