説明
セッションID、トークン、一時パスワードなどに、java.util.Random、Math.random()、ThreadLocalRandom、SplittableRandom のような暗号用途に適さない疑似乱数生成器(PRNG)を使うと、値を予測されるおそれがあります。攻撃者は観測した値からシードや内部状態を推定し、後続の値を予測したり推測の候補を絞ったりして、セッションやアカウントの乗っ取りを試みる可能性があります。
想定される影響
- セッションの乗っ取り: 予測可能なセッションIDやCookieにより、正規ユーザーになりすまされるおそれがあります。
- アカウントの乗っ取り: 一時パスワード、ログイントークン、メール確認用トークンを推測され、アカウントを奪われる可能性があります。
- 権限の悪用や昇格: アクセストークンやAPIキーを推測され、権限のない操作を実行されるおそれがあります。
- CSRF対策の回避: CSRFトークンが予測可能だと、偽造したリクエストが通る可能性があります。
- 機密情報の漏えい: 認証や認可の回避によって、保護された情報にアクセスされるおそれがあります。
対処方法
- セキュリティに関わる値には
java.security.SecureRandomを使います。- 例:
SecureRandom sr = new SecureRandom(); byte[] b = new byte[32]; sr.nextBytes(b);
- 例:
Random、Math.random()、ThreadLocalRandom、SplittableRandomをセッション、トークン、認証コードの生成に使わないでください。- 固定シードを指定せず、
new SecureRandom()に既定のエントロピーを取得させます。 - 少なくとも128ビット、できれば192~256ビットの乱数を生成し、URL-safe Base64でエンコードします。
- パスワード再設定やメール確認用のトークンには短い有効期限を設け、1回だけ使用できるようにします。
- 推測による攻撃を抑えるため、レート制限や試行回数の制限を適用します。
例
変更前
java
import javax.servlet.http.*;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;
public class WeakCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
long id = ThreadLocalRandom.current().nextLong(); // 暗号用途に適さないPRNG
String value = Long.toHexString(id);
resp.addHeader("Set-Cookie", "SID=" + value + "; HttpOnly; Secure");
resp.getWriter().println("ok");
}
}
変更後
java
import javax.servlet.http.*;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;
public class StrongCookieServlet extends HttpServlet {
private static final SecureRandom SR = new SecureRandom();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
byte[] token = new byte[32]; // 256ビットのエントロピー
SR.nextBytes(token);
String value = Base64.getUrlEncoder().withoutPadding().encodeToString(token);
resp.addHeader("Set-Cookie", "SID=" + value + "; HttpOnly; Secure; SameSite=Strict");
resp.getWriter().println("ok");
}
}
説明:
- 変更前:
ThreadLocalRandomは性能を重視したPRNGであり、暗号用途に必要な予測困難性を提供しません。この方法で作ったCookieは予測や推測が容易になり、セッションの乗っ取りにつながる可能性があります。 - 変更後:
SecureRandomで256ビットの乱数を生成し、URL-safe Base64でエンコードします。固定シードを使わず、十分なエントロピーを確保することで推測のリスクを抑えます。トークンの有効期限やサーバー側の検証は、別途実装する必要があります。