web-dev-qa-db-ja.com

byte []、KeyまたはStringとしての静的シークレット?

[〜#〜] jjwt [〜#〜] を使用して、サーバーアプリケーションでJWTを処理し始めました。

JWTシークレットはresourcesフォルダーに保存され、Propertiesクラスでシークレットをロードします。

[〜#〜] jjwt [〜#〜] は、JWTに署名するための3つのメソッドを提供します。1つはbyte[]を使用し、もう1つはStringを使用し、もう1つはKey

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

JwtBuilder signWith(SignatureAlgorithm var1, String var2);

JwtBuilder signWith(SignatureAlgorithm var1, Key var2);

質問:セキュリティ、文字セットなどに関して、どれを使用すべきかについての推奨事項はありますか?

StringPropertiesを返すので、しばらくの間、私はStringを使用します。

9
Paulo

JJWT> = 0.10.0の場合、生の文字列とBase64でエンコードされた文字列が混同されるため、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);
_

このメソッドは、文字列引数がBase64でエンコードされた秘密鍵バイト配列であることを想定しています。 は、署名キーとして、たとえばユーザーパスワードなどの一般的な文字列を想定していません。 JJWTはBase64エンコードを想定しています。これは、notBase64エンコードされた文字列パスワードを指定している場合、おそらく形式が正しくないか弱いキーを使用しているためです。

JWT JWA仕様 [〜#〜]は[〜#〜] 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サイトやツールは、この単純な間違いを犯しているだけです。古い文字列を入力または使用できると考えることができ、問題はありません。キーにWordsecretを事前に入力することさえできる人もいます(明らかに悪い考えであり、短すぎるため仕様に準拠していません!)。

物事を単純化するために、JJWTは、_io.jsonwebtoken.security.Keys_クラスの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_文字列はnotであり、誰にでも安全に表示できるとは見なされません。 Base64エンコーディングは暗号化ではありません-値は秘密にしておく必要があります。これをどのように行うかはあなた次第です(暗号化など)。

さて、JWSを作成するときは、couldその_base64Key_値を渡すことができ、JJWTは最初にそれをbase64デコードすることを知っています。実バイトを取得します。これは、署名の計算に使用されます。

_Jwts.builder()
    //...
    .signWith(SignatureAlgorithm.HS512, base64Key)
    .compact();
_

これは可能ですが、生の文字列とbase64でエンコードされた文字列があいまいであるため、JavaDocの上記の非推奨通知では推奨されません。

そのため、タイプセーフなKey引数を保証するJWTビルダーのsignWith(Key)またはsignWith(Key, SignatureAlgorithm)メソッドのいずれかを使用することをお勧めします。例えば:

_  Jwts.builder()
    //...
    .signWith(key) // or signWith(key, preferredSignatureAlgorithm)
    .compact();
_

signWith(Key)は、提供されたキーの強度に基づいて、JJWTが可能な限り最強のアルゴリズムを理解できるようにすることをお勧めします。 signWith(Key,SignatureAlgorithm)を使用すると、可能な限り強力なアルゴリズムが必要ない場合に、目的のアルゴリズムを指定できます。

どちらの方法も、RFCの最小要件を満たしていないKeyを拒否します。

17
Les Hazlewood