静态密钥为byte [],Key还是String?

Pau*_*ulo 9 java security jwt jjwt

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

我的JWT秘密将存储在resources文件夹中,我将在Properties课程中加载秘密.

JJWT提供了三种方法来签署JWT,一个用途byte[],其他用途String和其他用途Key:

JwtBuilder signWith(SignatureAlgorithm var1, byte[] var2);

JwtBuilder signWith(SignatureAlgorithm var1, String var2);

JwtBuilder signWith(SignatureAlgorithm var1, Key var2);
Run Code Online (Sandbox Code Playgroud)

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

一会儿,我站着String,因为Properties回来了String.

Les*_*ood 17

JavaDoc for signWith(SignatureAlgorithm var1, String var2)表示期望,甚至直观地命名方法参数:

/**
 * 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);
Run Code Online (Sandbox Code Playgroud)

因此,此方法期望字符串参数是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)                |
Run Code Online (Sandbox Code Playgroud)

许多在线JWT网站和工具只是弄错了 - 它们允许您认为您可以输入或使用任何旧字符串并且您很好.有些人甚至用这个词预先填充了密钥secret(显然是一个坏主意,甚至不符合规范,因为它太短了!).

因此,为了帮助您简化此操作,JJWT提供了一个实用程序,可帮助您生成足够的安全随机密钥,以便通过io.jsonwebtoken.security.Keys类进行符合规范的签名.

查看各种secretKeyFor方法,了解如何为HMAC签名生成良好的,符合规范的密钥.例如:

//creates a spec-compliant secure-random key:
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512
Run Code Online (Sandbox Code Playgroud)

如果您想将这些生成的密钥存储为String,您可能会对它们进行Base64编码:

String base64Key = Encoders.BASE64.encode(key.getEncoded());
Run Code Online (Sandbox Code Playgroud)

但请注意:结果base64Key字符串被认为不会向任何人显示.Base64编码不是加密 - 值仍然需要保密.你如何做到这一点取决于你(加密等).

现在,当创建JWS时,您可以传入该base64Key值,并且JJWT知道base64首先解码它以获取实际字节,然后用于计算签名:

Jwts.builder()
    //...
    .signWith(SignatureAlgorithm.HS512, base64Key)
    .compact();
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案。但是,请注意,在负载平衡的微服务环境中,应从 env var 读取密钥。 (2认同)