作为 byte[]、Key 或 String 的静态秘密?
Static secret as byte[], Key or String?
我已经开始使用 JJWT 在我的服务器应用程序上处理 JWT。
我的 JWT 机密将存储在 resources
文件夹中,我将使用 Properties
class.
加载机密
JJWT提供了三种签名JWT的方法,一种使用byte[]
,一种使用String
,另一种使用Key
:
JwtBuilder signWith(SignatureAlgorithm var1, byte[] var2);
JwtBuilder signWith(SignatureAlgorithm var1, String var2);
JwtBuilder signWith(SignatureAlgorithm var1, Key var2);
问题:关于安全,字符集等,有什么推荐的我应该使用哪一个?
有一段时间,我支持 String
,因为 Properties
return a String
.
随着 JJWT >= 0.10.0,signWith(SignatureAlgorithm var1, String var2)
已被弃用,因为原始字符串和 Base64 编码字符串之间存在混淆:
/**
* 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="
* Whosebug 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);
此方法要求字符串参数为 Base64 编码的密钥字节数组。它 不会 假定一个通用字符串(例如用户密码)作为签名密钥。 JJWT 采用 Base64 编码,因为如果您指定 不是 Base64 编码的字符串密码,您可能使用了格式不正确或弱的密钥。
JWT JWA 规范REQUIRES HMAC 签名密钥的长度等于或大于签名字节数组长度。
这意味着:
| 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
class 的 secretKeyFor
进行符合规范的签名方法。例如:
//creates a spec-compliant secure-random key:
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512
如果您想将生成的密钥存储为一个字符串,您大概可以对其进行 Base64 编码:
String base64Key = Encoders.BASE64.encode(key.getEncoded());
但请注意:生成的 base64Key
字符串 不 被认为可以安全地向任何人展示。 Base64 编码不是加密——值仍然需要保密。如何执行此操作取决于您(加密等)。
现在,当需要创建 JWS 时,您 可以 传入那个 base64Key
值,JJWT 知道首先对其进行 base64 解码以获得真正的字节,然后用于计算签名:
Jwts.builder()
//...
.signWith(SignatureAlgorithm.HS512, base64Key)
.compact();
虽然您可以这样做,但由于原始字符串和 base64 编码字符串之间存在歧义,因此根据 JavaDoc 中的上述弃用通知不建议这样做。
因此,建议使用 JWT 构建器的 signWith(Key)
或 signWith(Key, SignatureAlgorithm)
方法来保证类型安全的 Key
参数。例如:
Jwts.builder()
//...
.signWith(key) // or signWith(key, preferredSignatureAlgorithm)
.compact();
建议使用 signWith(Key)
让 JJWT 根据您提供的密钥的强度找出可能的最强算法。 signWith(Key,SignatureAlgorithm)
如果您不想要最强的算法,则允许您指定所需的算法。
这两种方法都会拒绝任何不符合最低 RFC 要求的 Key
。
我已经开始使用 JJWT 在我的服务器应用程序上处理 JWT。
我的 JWT 机密将存储在 resources
文件夹中,我将使用 Properties
class.
JJWT提供了三种签名JWT的方法,一种使用byte[]
,一种使用String
,另一种使用Key
:
JwtBuilder signWith(SignatureAlgorithm var1, byte[] var2);
JwtBuilder signWith(SignatureAlgorithm var1, String var2);
JwtBuilder signWith(SignatureAlgorithm var1, Key var2);
问题:关于安全,字符集等,有什么推荐的我应该使用哪一个?
有一段时间,我支持 String
,因为 Properties
return a String
.
随着 JJWT >= 0.10.0,signWith(SignatureAlgorithm var1, String var2)
已被弃用,因为原始字符串和 Base64 编码字符串之间存在混淆:
/**
* 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="
* Whosebug 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);
此方法要求字符串参数为 Base64 编码的密钥字节数组。它 不会 假定一个通用字符串(例如用户密码)作为签名密钥。 JJWT 采用 Base64 编码,因为如果您指定 不是 Base64 编码的字符串密码,您可能使用了格式不正确或弱的密钥。
JWT JWA 规范REQUIRES HMAC 签名密钥的长度等于或大于签名字节数组长度。
这意味着:
| 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
class 的 secretKeyFor
进行符合规范的签名方法。例如:
//creates a spec-compliant secure-random key:
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512
如果您想将生成的密钥存储为一个字符串,您大概可以对其进行 Base64 编码:
String base64Key = Encoders.BASE64.encode(key.getEncoded());
但请注意:生成的 base64Key
字符串 不 被认为可以安全地向任何人展示。 Base64 编码不是加密——值仍然需要保密。如何执行此操作取决于您(加密等)。
现在,当需要创建 JWS 时,您 可以 传入那个 base64Key
值,JJWT 知道首先对其进行 base64 解码以获得真正的字节,然后用于计算签名:
Jwts.builder()
//...
.signWith(SignatureAlgorithm.HS512, base64Key)
.compact();
虽然您可以这样做,但由于原始字符串和 base64 编码字符串之间存在歧义,因此根据 JavaDoc 中的上述弃用通知不建议这样做。
因此,建议使用 JWT 构建器的 signWith(Key)
或 signWith(Key, SignatureAlgorithm)
方法来保证类型安全的 Key
参数。例如:
Jwts.builder()
//...
.signWith(key) // or signWith(key, preferredSignatureAlgorithm)
.compact();
建议使用 signWith(Key)
让 JJWT 根据您提供的密钥的强度找出可能的最强算法。 signWith(Key,SignatureAlgorithm)
如果您不想要最强的算法,则允许您指定所需的算法。
这两种方法都会拒绝任何不符合最低 RFC 要求的 Key
。