首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >静态秘密如byte[],键还是字符串?

静态秘密如byte[],键还是字符串?
EN

Stack Overflow用户
提问于 2016-10-26 02:48:48
回答 1查看 21.5K关注 0票数 20

我已经开始使用JJWT在我的服务器应用程序上处理JWT。

我的JWT秘密将存储在resources文件夹中,我将用Properties类加载这个秘密。

JJWT提供了三种签署JWT的方法,一个使用byte[],另一个使用String,另一个使用Key

代码语言:javascript
运行
复制
JwtBuilder signWith(SignatureAlgorithm var1, byte[] var2);

JwtBuilder signWith(SignatureAlgorithm var1, String var2);

JwtBuilder signWith(SignatureAlgorithm var1, Key var2);

的问题:关于安全性、字符集和其他方面,有哪些建议我应该使用吗?

有一段时间,我支持String,因为Properties返回一个String

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-27 00:43:04

对于JJWT >= 0.10.0,由于原始字符串和Base64 64编码字符串之间的混淆,signWith(SignatureAlgorithm var1, String var2)已不再受欢迎:

代码语言:javascript
运行
复制
/**
 * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
 *
 * <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
 * byte array is used to invoke {@link #signWith(SignatureAlgorithm, byte[])}.</p>
 *
 * <h4>Deprecation Notice: Deprecated as of 0.10.0, will be removed in the 1.0 release.</h4>
 *
 * <p>This method has been deprecated because the {@code key} argument for this method can be confusing: keys for
 * cryptographic operations are always binary (byte arrays), and many people were confused as to how bytes were
 * obtained from the String argument.</p>
 *
 * <p>This method always expected a String argument that was effectively the same as the result of the following
 * (pseudocode):</p>
 *
 * <p>{@code String base64EncodedSecretKey = base64Encode(secretKeyBytes);}</p>
 *
 * <p>However, a non-trivial number of JJWT users were confused by the method signature and attempted to
 * use raw password strings as the key argument - for example {@code signWith(HS256, myPassword)} - which is
 * almost always incorrect for cryptographic hashes and can produce erroneous or insecure results.</p>
 *
 * <p>See this
 * <a href="https://stackoverflow.com/questions/40252903/static-secret-as-byte-key-or-string/40274325#40274325">
 * StackOverflow answer</a> explaining why raw (non-base64-encoded) strings are almost always incorrect for
 * signature operations.</p>
 *
 * <p>To perform the correct logic with base64EncodedSecretKey strings with JJWT >= 0.10.0, you may do this:
 * <pre><code>
 * byte[] keyBytes = {@link Decoders Decoders}.{@link Decoders#BASE64 BASE64}.{@link Decoder#decode(Object) decode(base64EncodedSecretKey)};
 * Key key = {@link Keys Keys}.{@link Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor(keyBytes)};
 * jwtBuilder.signWith(key); //or {@link #signWith(Key, SignatureAlgorithm)}
 * </code></pre>
 * </p>
 *
 * <p>This method will be removed in the 1.0 release.</p>
 *
 * @param alg                    the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
 * @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the
 *                               JWT.
 * @return the builder for method chaining.
 * @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification as
 *                             described by {@link SignatureAlgorithm#forSigningKey(Key)}.
 * @deprecated as of 0.10.0: use {@link #signWith(Key)} or {@link #signWith(Key, SignatureAlgorithm)} instead.  This
 * method will be removed in the 1.0 release.
 */
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey);

此方法期望字符串参数为byte 64编码的密钥字节数组。它不假设通用字符串(例如用户密码)作为签名密钥。JJWT采用Base64编码,因为如果您指定的字符串密码不是Base64 64编码的,那么您可能使用的是格式错误或弱键。

https://www.rfc-editor.org/rfc/rfc7518#section-3.2签名密钥的长度等于或大于签名字节数组长度的JWT规范。

这意味着:

代码语言:javascript
运行
复制
| If you're signing with: | your key (byte array) length MUST be: |
| ----------------------- | ------------------------------------- |
| HMAC SHA 256            | >= 256 bits (32 bytes)                |
| HMAC SHA 384            | >= 384 bits (48 bytes)                |
| HMAC SHA 512            | >= 512 bits (64 bytes)                |

很多在线的JWT站点和工具就是搞错了--它们让你认为你可以输入或使用任何旧的字符串,而且你很好。有些人甚至甚至预先填充了单词secret (显然是个坏主意,甚至不符合规范,因为它太短了!)

为了帮助您简化事情,JJWT提供了一个实用程序,帮助您生成足够的安全随机密钥,适合通过io.jsonwebtoken.security.Keys类的secretKeyFor方法进行符合规范的签名。例如:

代码语言:javascript
运行
复制
//creates a spec-compliant secure-random key:
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512

如果要将生成的密钥存储为字符串,可以假定是Base64对其进行编码:

代码语言:javascript
运行
复制
String base64Key = Encoders.BASE64.encode(key.getEncoded());

但是请注意:生成的base64Key字符串被认为是不安全的,不能向任何人显示。Base64编码不是加密--这个值仍然需要保密。你是如何做到这一点的(加密等等)。

现在,当创建JWS的时候,您可以传入该base64Key值,JJWT知道首先对其进行base64解码,以获得实际字节,然后使用这些字节来计算签名:

代码语言:javascript
运行
复制
Jwts.builder()
    //...
    .signWith(SignatureAlgorithm.HS512, base64Key)
    .compact();

虽然您可以这样做,但由于原始字符串和base64 64编码字符串之间的模糊性,不建议在JavaDoc中按照上面的弃用通知进行说明。

因此,建议使用JWT构建器的signWith(Key)signWith(Key, SignatureAlgorithm)方法来保证类型安全的Key参数。例如:

代码语言:javascript
运行
复制
  Jwts.builder()
    //...
    .signWith(key) // or signWith(key, preferredSignatureAlgorithm)
    .compact();

建议使用signWith(Key)来让JJWT根据所提供密钥的强度确定最强大的算法。如果您不想使用最强大的算法,signWith(Key,SignatureAlgorithm)允许您指定所需的算法。

这两种方法都将拒绝任何不符合最低RFC要求的Key

票数 36
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40252903

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档