静态机密作为字节 []、密钥还是字符串?
我已经开始使用 JJWT 来处理我的服务器应用程序上的 JWT.
I have started to work with JJWT to handle JWT on my server application.
我的 JWT 机密将存储在 resources
文件夹中,我将使用 Properties
类加载该机密.
My JWT secret will be stored at resources
folder and I will load the secret with Properties
class.
JJWT 提供了三种对 JWT 进行签名的方法,一种使用 byte[]
,其他使用String
,其他使用Key
:
The JJWT provides three methods to sign the JWT, one uses byte[]
, other uses String
and the other uses Key
:
JwtBuilder signWith(SignatureAlgorithm var1, byte[] var2);
JwtBuilder signWith(SignatureAlgorithm var1, String var2);
JwtBuilder signWith(SignatureAlgorithm var1, Key var2);
问题:关于安全、字符集和其他方面,我应该使用哪一个有什么建议?
The question: Regarding security, charset and other things, there are any recommendations of which one I should use?
暂时,我支持 String
,因为 Properties
返回一个 String
.
For while, I stand with String
, since Properties
return a String
.
推荐答案
在 JJWT >= 0.10.0 的情况下,signWith(SignatureAlgorithm var1, String var2)
已被弃用,因为它们之间存在混淆字符串和 Base64 编码的字符串:
With JJWT >= 0.10.0, signWith(SignatureAlgorithm var1, String var2)
has been deprecated because of the confusion between raw strings and Base64-encoded strings:
/**
* 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);
此方法要求字符串参数是 Base64 编码的密钥字节数组.它不假设一个通用字符串,例如用户密码,作为签名密钥.JJWT 采用 Base64 编码,因为如果您指定的字符串密码不是 Base64 编码的,那么您可能使用了格式不正确或弱的密钥.
This method expects the string argument to be a Base64-encoded secret key byte array. It does not assume a general string, like a user password for example, as the signing key. JJWT assumes Base64 encoding because if you're specifying a string password that is not Base64-encoded, you're probably using a poorly formed or weak key.
JWT JWA 规范要求 HMAC 签名密钥的长度等于或大于签名字节数组长度.
The JWT JWA specification REQUIRES that HMAC signing keys have lengths equal to or greater than the signature byte array length.
这意味着:
| 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
这个词预先填充密钥(显然是个坏主意,甚至不符合规范,因为它太短了!).
Many online JWT sites and tools just just get this plain wrong - they allow you to think that you could type in or use any old string and you're good. Some go as far as even pre-populating the key with the word secret
(clearly a bad idea and not even spec-compliant because it's too short!).
为了帮助您简化事情,JJWT 提供了一个实用程序来帮助您生成足够的安全随机密钥,以通过 io.jsonwebtoken.security.Keys
类的 secretKeyFor 进行符合规范的签名
方法.例如:
To help simplify things for you, JJWT provides a utility to help you generate sufficient secure-random keys suitable for spec-compliant signing via the io.jsonwebtoken.security.Keys
class's secretKeyFor
method. For example:
//creates a spec-compliant secure-random key:
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512
如果你想将生成的密钥存储为字符串,你可以推测它是 Base64 编码:
If you wanted to store the generated key as a String, you could presumably Base64 encode it:
String base64Key = Encoders.BASE64.encode(key.getEncoded());
但请注意:生成的 base64Key
字符串不被认为可以安全地显示给任何人.Base64 编码不是加密 - 该值仍然需要保密.如何执行此操作取决于您(加密等).
But note: the resulting base64Key
string is not considered safe to show to anyone. Base64 encoding is not encryption - the value still needs to be kept secret. How you do this is up to you (encrypt it, etc).
现在,当需要创建 JWS 时,您可以传入该 base64Key
值,JJWT 知道首先对其进行 base64 解码以获取实际字节,然后用于计算签名:
Now, when it is time to create a JWS, you could pass in that base64Key
value, and JJWT knows to base64 decode it first to get the real bytes, which are then used to compute the signature:
Jwts.builder()
//...
.signWith(SignatureAlgorithm.HS512, base64Key)
.compact();
虽然您可以这样做,但由于原始字符串和 base64 编码字符串之间的歧义,不建议按照 JavaDoc 中的上述弃用通知.
And while you could do this, it is not recommended per the above deprecation notice in the JavaDoc due to the ambiguity between raw strings and base64-encoded strings.
因此,建议使用 JWT 构建器的 signWith(Key)
或 signWith(Key, SignatureAlgorithm)
方法来保证类型安全 键
参数.例如:
As a result, it is recommended to use either the JWT builder's signWith(Key)
or signWith(Key, SignatureAlgorithm)
methods which guarantee a type-safe Key
argument. For example:
Jwts.builder()
//...
.signWith(key) // or signWith(key, preferredSignatureAlgorithm)
.compact();
signWith(Key)
建议让 JJWT 根据您提供的密钥的强度找出可能的最强算法.signWith(Key,SignatureAlgorithm)
允许您指定所需的算法,如果您不想要最强的算法.
signWith(Key)
is recommended to let JJWT figure out the strongest algorithm possible based on the strength of your supplied key. signWith(Key,SignatureAlgorithm)
allows you to specify a desired algorithm if you don't want the strongest possible one.
这两种方法都会拒绝任何不符合最低 RFC 要求的 Key
.
Both methods will reject any Key
that doesn't meet the minimum RFC requirements.
相关文章