1. ホーム
  2. java

[解決済み] 英数字のランダムな文字列を生成する方法

2022-03-19 09:53:41

質問

を探していたのですが シンプル 擬似的にランダムな英数字の文字列を生成するためのJavaアルゴリズム。 私の状況下では、これはセッション/キー識別子として使用され、quot;likely" で一意となります。 500K+ を生成します(私のニーズでは、これ以上高度なものは必要ありません)。

理想を言えば、一意性の必要性に応じて長さを指定できるようにしたいですね。例えば、長さ12の生成文字列は次のようになります。 "AEYGF7K0DM1X" .

解決方法は?

アルゴリズム

ランダムな文字列を生成するには、許容される記号のセットからランダムに選んだ文字を、目的の長さになるまで連結する。

実装

以下は、ランダムな識別子を生成するための、非常にシンプルで柔軟なコードです。 以下の情報をお読みください。 は、重要なアプリケーションノートです。

public class RandomString {

    /**
     * Generate a random string.
     */
    public String nextString() {
        for (int idx = 0; idx < buf.length; ++idx)
            buf[idx] = symbols[random.nextInt(symbols.length)];
        return new String(buf);
    }

    public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static final String lower = upper.toLowerCase(Locale.ROOT);

    public static final String digits = "0123456789";

    public static final String alphanum = upper + lower + digits;

    private final Random random;

    private final char[] symbols;

    private final char[] buf;

    public RandomString(int length, Random random, String symbols) {
        if (length < 1) throw new IllegalArgumentException();
        if (symbols.length() < 2) throw new IllegalArgumentException();
        this.random = Objects.requireNonNull(random);
        this.symbols = symbols.toCharArray();
        this.buf = new char[length];
    }

    /**
     * Create an alphanumeric string generator.
     */
    public RandomString(int length, Random random) {
        this(length, random, alphanum);
    }

    /**
     * Create an alphanumeric strings from a secure generator.
     */
    public RandomString(int length) {
        this(length, new SecureRandom());
    }

    /**
     * Create session identifiers.
     */
    public RandomString() {
        this(21);
    }

}

使用例

8文字識別子の安全でないジェネレータを作成します。

RandomString gen = new RandomString(8, ThreadLocalRandom.current());

セッション識別子用のセキュアなジェネレータを作成します。

RandomString session = new RandomString();

印刷用の読みやすいコードでジェネレータを作成します。文字列は、使用する記号の数が少ないことを補うために、完全な英数字の文字列よりも長くなっています。

String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);

セッション識別子として使用する

ユニークである可能性が高いセッション識別子を生成することは十分ではなく、単純なカウンターを使用することもできます。予測可能な識別子が使われると、攻撃者はセッションをハイジャックします。

長さと安全性の間には緊張関係があります。短い識別子は可能性が少ないため、推測が容易です。しかし、長い識別子はストレージと帯域幅を消費します。記号のセットを大きくすることは有効ですが、識別子がURLに含まれていたり、手で再入力されたりすると、エンコーディングの問題が発生する可能性があります。

セッション識別子のランダム性(エントロピー)の基礎となるソースは、暗号用に設計された乱数発生器から得る必要があります。しかし、これらの生成器の初期化には計算コストがかかったり、時間がかかったりすることがあるので、可能な限り再利用するように努力する必要があります。

オブジェクト識別子としての利用

すべての用途でセキュリティが必要なわけではありません。ランダム割り当ては、複数のエンティティが調整やパーティショニングを行わずに共有スペースに識別子を生成する効率的な方法です。特にクラスタや分散環境では、調整に時間がかかることがあります。また、空間を分割すると、エンティティが小さすぎたり大きすぎたりする共有になってしまうという問題が発生します。

予測できないようにする対策をとらずに生成された識別子は、多くのWebアプリケーションで起こるように、攻撃者が閲覧・操作できる可能性がある場合、別の手段で保護する必要があります。攻撃者がアクセス許可なしに識別子を推測できるようなオブジェクトを保護するために、別の認可システムを用意すべきです。

また、識別子の総数を想定して、衝突が起こりにくい十分な長さの識別子を使用するよう注意しなければならない。これは「誕生日のパラドックス」と呼ばれています。 衝突の確率を表す。 p であり、約n 2 /(2q x ), ここで n は実際に生成された識別子の数である。 q はアルファベット中の異なる記号の数であり x は識別子の長さです。これは2などの非常に小さな数であるべきです。 -50 またはそれ以下である。

これを計算すると、500k個の15文字識別子の間で衝突する確率は、約2 -52 これは、宇宙線などによる未検出のエラーよりも低い可能性でしょう。

UUIDとの比較

その仕様によると UUID は予測不可能なように設計されておらず はいけません。 をセッション識別子として使用します。

UUIDの標準的なフォーマットは、多くのスペースを必要とします。36文字で122ビットのエントロピーしかありません。(ランダムなUUIDのすべてのビットがランダムに選択されるわけではありません。)ランダムに選択された英数字の文字列は、わずか21文字でより多くのエントロピーをパックしています。

UUIDは柔軟性がなく、標準的な構造とレイアウトを持っています。これはUUIDの長所でもあり、短所でもあります。外部と共同作業をする場合、UUIDが提供する標準化は役に立つかもしれません。純粋に内部で使用する場合は、非効率的です。