golang使用JWX进行认证和加密

最近看了一个名为go-auth的库,它将JWT作为HTTP cookie对用户进行验证,但这个例子中缺少了对JWT的保护,由此进行了一些针对JWX的研究。

下面描述来自golang-jwt的官方描述:

概述

Bearer.headerClaim

签名 vs 加密

一个token是一个签名的json对象,涉及两方面的内容:

  • token的创建者拥有签名的secret
  • 数据一旦被签名就不能修改
JWE

选择签名方法

签名方法有很多种,在使用前可能需要花时间挑选合适的签名方法,主要考量点为:对称和非对称。

[]byte

非对称签名,如RSA,则使用了不同的密钥进行签名和token验证,因此可以使用私钥生成token,并允许消费者使用公钥进行验证。

JWT和OAuth

这里提一下,OAuth和JWT并不是一回事,一个JWT token只是一个简单的被签名的JSON对象,可以用在所需要的地方,最常见的方式是用在OAuth2认证中。

下面描述了二者是如何交互的:

  • OAuth是一种允许身份提供者与用户登录的服务分离的协议。例如,你可以使用Facebook登陆不同的服务(Yelp、Spotify等),此时用的就是OAuth。
  • OAuth定义了几种传递身份验证数据的选项,其中流行的一种方式称为"bearer token",一个bearer token就是一个只能被已认证的用户持有的简单字符串,即通过提供该token来进行身份认证。从这里可以看出JWT可以作为一种bearer token。
  • 由于bearer token用于认证,因此私密性很重要,这也是为什么通常会通过SSL来使用bearer token。

JWT的用法

从上面的官方描述中可以看到JWT其实就是一个字符串,其分为三段:header,主要指定签名方法;claim,用于提供用户身份数据;signature,使用header中指定的签名方法进行签名,签名时主要使用了三个基础数据:

签名密钥:在对称签名(如HMAC)中作为哈希数据的一部分,在非对称签名(如ECDSA)中则作为私钥。在JWT的签名和验证过程中都需要使用到密钥。

claim:主要包含了JWT相关的信息,用户可以扩展自己的claim信息。签名方法会使用这部分信息进行签名。如下是标准的claims,可以看到这部分信息其实与SSL证书中的字段雷同。

另外需要注意的是,JWT是使用明文交互的,其中claim中包含了用户的敏感信息,因此需要使用JWE进行加密。

在了解JWT之前可以看下几个重要的术语:

headerclaimssignature
alg

JWE(EncryptedJWT):用于加密payload,如JWT,主要字段如下:

JWK:是一个JSON数据结构,用于JWS的签名验证以及JWE的加解密,主要字段如下:

例子

lestrrat-go
jwt.NewBuilderjwt.New
jwt.SignstdToken[]byte
jwt.ParsestdTokenjwt.Sign
jws.sign[]bytejwt.SignstdToken
jws.parse
jwe.Encrypt
jwe.Decrypt

下面看下如何生成JWT,以及如何结合使用JWE和JWK对其进行加密。

Example 1

下面jwt使用对称方式进行签名/解析,jwe使用非对称方式进行加解密

Example 2

下面使用非对称方式进行签名/解析:

Example 3

jwk.ReadFilejwk.Fetch

lestrrat-go的官方文档中给出了很多指导。

参考