首页 > Web开发 > 详细

JSON Web Signature 规范解析

时间:2019-12-15 10:51:06      阅读:117      评论:0      收藏:0      [点我收藏+]

 

JWS 也就是 Json Web Signature,是构造 JWT 的基础结构(JWT 其实涵盖了 JWS 和 JWE 两类,其中 JWT 的载荷还可以是嵌套的 JWT),包括三部分 JOSE Header、JWS Payload、JWS Signature。

这里的 Signature 可以有两种生成方式,一种是标准的签名,使用非对称加密,因为私钥的保密性,能够确认签名的主体,同时能保护完整性;另一种是消息认证码 MAC(Message Authentication Code),使用对称秘钥,该秘钥需要在签发、验证的多个主体间共享,因此无法确认签发的主体,只能起到保护完整性的作用。

JWS 最终有两种序列化的表现形式,一种是 JWS Compact Serialization,为一串字符;另一种是 JWS JSON Serialization,是一个标准的 Json 对象,允许为同样的内容生成多个签名/消息认证码。
技术分享图片

JWS Compact Serialization,各部分以 ‘.’ 分隔。

BASE64URL(UTF8(JWS Protected Header)) || ’.’ ||
BASE64URL(JWS Payload) || ’.’ ||
BASE64URL(JWS Signature)

JWS Json Serialization 还可以分为两种子格式:通用、扁平。

通用格式,最外层为 payload、signatures。signatures 中可以包含多个 json 对象,内层的 json 对象由 protected、header、signature 组成。不同的 protected header 生成不同的 Signature。

{
    "payload": "<payload contents>",
    "signatures": 
    [
        {
            "protected": "<integrity-protected header 1 contents>",
            "header": "<non-integrity-protected header 1 contents>",
            "signature": "<signature 1 contents>"
        },
        ...
        {
            "protected": "<integrity-protected header N contents>",
            "header": "<non-integrity-protected header 1 contents>",
            "signature": "<signature N contents>"
        }
    ]
}

扁平格式,就是为只有一个 signature/mac 准备的。

{
    "payload": "<payload contents>",
    "protected": "<integrity-protected header contents>",
    "header": "<non-integrity-protected header contents>",
    "signature": "<signature contents>"
}

JOSE Header:Json Object Signing and Encryption Header。描述加密行为及其他用到的参数,是 JWS Protected/Unprotected Header 的合集。

JWS Protected Header,有完整性保护的头参数。

JWS Unprotected Header,无完整性保护头参数,仅出现在 JWS Json Serialization 格式中。

以下列出了 JOSE Header 中的规定参数,各参数详细信息请参考 rfc7515

头参数全称解释必选
alg algorithm 指定签名算法,为 none 时,表示不使用签名来保护完整性 是
jku JWK set URL 签名所用 key 对应公匙所在的 URI 否
jwk json web key 签名所用 key 对应的公匙 否
kid key id 签名所用 key 的 id 否
typ Type 指明整个 jws 的媒体类型,JOSE 意味着为compact,JOSE+JSON意味着为json 否
cty Content Type 载荷的媒体类型 否
crit Critical 此字段列出的扩展头参数必须被接收者理解并处理,否则该 jws 无效,该字段为数组格式 否
x5u X.509 URL – 否
x5c X.509 Certificate Chain – 否
x5t X.509 Certificate SHA-1 Thumbprint – 否
x5t#S256 X.509 Certificate SHA-256 Thumbprint – 否
# crit 参数例子
{
    "alg":"ES256",
    "crit":["exp","iss"],
    "exp":1363284000,
    "iss":"test"
}

以下为 rfc7515 中提供的一个案例,使用 HMAC_SHA256 生成 JWS Signature。

1. 头部就是一个紧凑的字符串,不换行,也无空格。

Header = {“typ”:“JWT”,“alg”:“HS256”}

base64url(Header) = eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9

import base64
header_encoded = base64.urlsafe_b64encode(b‘{"typ":"JWT","alg":"HS256"}‘)
print(header_encoded)

2. 载荷是一个包括了换行和空格的 json 对象,换行取 win 系统的 CRLF,且除第一行外,每一行开头有一个空格,行尾无空格。

技术分享图片

Payload = {“iss”:“joe”,\r\n “exp”:1300819380,\r\n “http://example.com/is_root”:true}

base64url(Payload) = eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ

import base64
Payload = {"iss":"joe",\r\n "exp":1300819380,\r\n "http://example.com/is_root":true}
payload_encoded = (b‘{"iss":"joe",\r\n "exp":1300819380,\r\n "http://example.com/is_root":true}‘)
print(payload_encoded)

3. 生成 Signature 时将头部和载荷视为一体

Message = ASCII(BASE64URL(UTF8(JWS Protected Header)) || ’.’ || BASE64URL(JWS Payload))

HMAC_SHA256 签名时需要用到对称密匙 Key,这里的 Key 是预先商量好的

Key = AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow

因为 Key 也是 base64url 编码后的内容,所以要获取 Key 的字节数组需要 base64url 解码一把,解码时由于 Key 的长度为 86,86%4=2,需要添加 ‘==’ 后再进行解码

# 也即解码时用的是这个
Key = AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow==

Signature = base64url( HMAC_SHA256(Message, Key) )

最后得到签名为 dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk=

import hashlib
import hmac
import base64

message = bytes(‘eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ‘,‘ascii‘)

secret = base64.urlsafe_b64decode(‘AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow==‘)

signature = base64.urlsafe_b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())

print(signature)

去掉多余的 ‘=’ ,就是最终的 Signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

这样,最终的 JWS 就为(换行是为了方便看,实际就是一串)

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

当然,实际中可能会选用 RSA 之类的算法来进行签名,可参考 RFC 文档中的案例。

参考文档: rfc7515

 

JSON Web Signature 规范解析

原文:https://www.cnblogs.com/read-the-spring-and-autumn-annals-in-night/p/12041911.html

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!