• JWT 签名算法 HS256、RS256 及 ES256 及密钥生成


    签名算法

    介绍具体的 JWT 签名算法前,先解释一下签名、摘要/指纹、加密这几个名词的含义:

    1. 数字签名(Digital Signature):就和我们日常办理各种手续时需要在文件上签上自己的名字一样,数字签名的主要用途也是防止伪造。
    2. 数字摘要(digest)/数字指纹(fingerprint): 指的都是数据的 Hash 值。
    3. 加密算法:这个应该不需要解释,就是对数据进行加密。。

    数字签名的具体实现,通常是先对数据进行一次 Hash 摘要(SHA1/SHA256/SHA512 等),然后再使用非对称加密算法(RSA/ECC 等)对这个摘要进行加密,这样得到的结果就是原始数据的一个签名。

    用户在验证数据时,只需要使用公钥解密出 Hash 摘要,然后自己再对数据进行一次同样的摘要,对比两个摘要是否相同即可。

    P.S. 在 Android/IOS 开发中,经常会遇到各类 API 或者 APP 商店要求提供 APP 的签名,还指明需要的是 MD5/SHA1 值。
    这个地方需要填的 MD5/SHA1 值,实际上只是你「签名证书(=公钥+证书拥有者信息)」的「数字指纹」,和 JWT 的签名不是一回事。

    前言

    JWT 规范的详细说明请见「参考」部分的链接。这里主要说明一下 JWT 最常见的几种签名算法(JWA):HS256(HMAC-SHA256) 、RS256(RSA-SHA256) 还有 ES256(ECDSA-SHA256)。

    这三种算法都是一种消息签名算法,得到的都只是一段无法还原的签名。区别在于消息签名签名验证需要的 「key」不同。

    1. HS256 使用同一个「secret_key」进行签名与验证。一旦 secret_key 泄漏,就毫无安全性可言了。
      • 因此 HS256 只适合集中式认证,签名和验证都必须由可信方进行。
    2. RS256 是使用 RSA 私钥进行签名,使用 RSA 公钥进行验证。公钥即使泄漏也毫无影响,只要确保私钥安全就行。
      • RS256 可以将验证委托给其他应用,只要将公钥给他们就行。
    3. ES256 和 RS256 一样,都使用私钥签名,公钥验证。算法速度上差距也不大,但是它的签名长度相对短很多(省流量),并且算法强度和 RS256 差不多。

    对于单体应用而言,HS256 和 RS256 的安全性没有多大差别。
    而对于需要进行多方验证的微服务架构而言,显然 RS256/ES256 安全性更高。
    只有 user 微服务需要用 RSA 私钥生成 JWT,其他微服务使用公钥即可进行签名验证,私钥得到了更好的保护。

    RFC 7518 - JSON Web Algorithms (JWA) 中给出的 JWT 算法列表如下:

       +--------------+-------------------------------+--------------------+
       | "alg" Param  | Digital Signature or MAC      | Implementation     |
       | Value        | Algorithm                     | Requirements       |
       +--------------+-------------------------------+--------------------+
       | HS256        | HMAC using SHA-256            | Required           |
       | HS384        | HMAC using SHA-384            | Optional           |
       | HS512        | HMAC using SHA-512            | Optional           |
       | RS256        | RSASSA-PKCS1-v1_5 using       | Recommended        |
       |              | SHA-256                       |                    |
       | RS384        | RSASSA-PKCS1-v1_5 using       | Optional           |
       |              | SHA-384                       |                    |
       | RS512        | RSASSA-PKCS1-v1_5 using       | Optional           |
       |              | SHA-512                       |                    |
       | ES256        | ECDSA using P-256 and SHA-256 | Recommended+       |
       | ES384        | ECDSA using P-384 and SHA-384 | Optional           |
       | ES512        | ECDSA using P-521 and SHA-512 | Optional           |
       | PS256        | RSASSA-PSS using SHA-256 and  | Optional           |
       |              | MGF1 with SHA-256             |                    |
       | PS384        | RSASSA-PSS using SHA-384 and  | Optional           |
       |              | MGF1 with SHA-384             |                    |
       | PS512        | RSASSA-PSS using SHA-512 and  | Optional           |
       |              | MGF1 with SHA-512             |                    |
       | none         | No digital signature or MAC   | Optional           |
       |              | performed                     |                    |
       +--------------+-------------------------------+--------------------+
    
       The use of "+" in the Implementation Requirements column indicates
       that the requirement strength is likely to be increased in a future
       version of the specification.
    

    可以看到被标记为 Recommended 的只有 RS256 和 ES256。

    ES256 使用 ECDSA 进行签名,它的安全性和运算速度目前和 RS256 差距不大,但是拥有更短的签名长度。
    对于需要频繁发送的 JWT 而言,更短的长度长期下来可以节约大量流量。

    因此更推荐使用 ES256 算法。

    使用 OpenSSL 生成 RSA/ECC 公私钥

    RS256 使用 RSA 算法进行签名,可通过如下命令生成 RSA 密钥:

    # 1. 生成 2048 位(不是 256 位)的 RSA 密钥
    openssl genrsa -out rsa-private-key.pem 2048
    
    # 2. 通过密钥生成公钥
    openssl rsa -in rsa-private-key.pem -pubout -out rsa-public-key.pem
    

    ES256 使用 ECDSA 算法进行签名,该算法使用 ECC 密钥,生成命令如下:

    # 1. 生成 ec 算法的私钥,使用 prime256v1 算法,密钥长度 256 位。(强度大于 2048 位的 RSA 密钥)
    openssl ecparam -genkey -name prime256v1 -out ecc-private-key.pem
    # 2. 通过密钥生成公钥
    openssl ec -in ecc-private-key.pem -pubout -out ecc-public-key.pem
    

    参考

  • 相关阅读:
    Arrays.fill方法的陷阱
    彻底弄懂最短路径问题
    《c++primer》疑惑记录
    C++ 隐含的this 指针
    c++ 内存分配
    抽象 与 封装 区别
    iconv 文件编码转换
    python中文分词工具——结巴分词
    词形变换和词干提取工具(英文)
    python 绘图工具 matplotlib 入门
  • 原文地址:https://www.cnblogs.com/kirito-c/p/12402066.html
Copyright © 2020-2023  润新知