ランダム文字列生成は「安全なカギ札を作る作業」
業務システムでは、一時パスワード、認証コード、トークン、セッションID、テストデータ用のダミー値など、「誰ともかぶらず、予測されにくい文字列」が欲しくなる場面がたくさん出てきます。
このときに使うのが「ランダム文字列生成」です。
ただし、なんとなく Random を使って適当に文字を並べるだけだと、「推測されやすい」「セキュリティ的に弱い」「用途に合っていない」といった問題が起きます。
ここでは、初心者向けに「まず押さえるべき基本」と「業務で本当に使えるユーティリティの形」を、例題付きで丁寧に整理していきます。
まずは基本:英数字ランダム文字列の作り方
Random を使った一番シンプルな実装
「とりあえず英数字のランダム文字列が欲しい」という一番基本的なパターンから見ていきます。
import java.util.Random;
public class RandomStrings {
private static final String CHARSET =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
public static String randomString(int length) {
Random random = new Random();
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int index = random.nextInt(CHARSET.length());
sb.append(CHARSET.charAt(index));
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(randomString(16)); // 例: "aZ3k9Pq1Xy0B7cD2"
}
}
Javaやっていることはとてもシンプルで、「使ってよい文字の一覧(CHARSET)を用意し、その中からランダムに 1 文字ずつ選んで連結する」というだけです。
このパターンは、テストデータ生成や「そこまでセキュリティが重要でない一時的な識別子」など、ライトな用途なら十分使えます。
ただし、Random はあくまで一般用途向けの疑似乱数であり、「セキュリティ的に強い乱数」ではありません。
一時パスワードや認証トークンのように「攻撃者に予測されたくない」用途では、次に説明する SecureRandom を使う必要があります。
セキュリティが絡むなら SecureRandom 一択
SecureRandom が必要になる理由
java.security.SecureRandom は、「暗号用途にも耐えられる、予測されにくい乱数」を生成するためのクラスです。
普通の Random は内部状態が比較的単純で、十分な観測があれば将来の値を推測される可能性がありますが、SecureRandom はそのリスクを下げるように設計されています。
パスワード、トークン、セッションID、認証コードなど、「推測されると困るもの」を作るときは、必ず SecureRandom を使う、と覚えておいてください。
SecureRandom を使った安全なランダム文字列
先ほどの実装を、SecureRandom ベースに書き換えてみます。
import java.security.SecureRandom;
public class SecureRandomStrings {
private static final String CHARSET =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
public static String secureRandomString(int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int index = SECURE_RANDOM.nextInt(CHARSET.length());
sb.append(CHARSET.charAt(index));
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(secureRandomString(32)); // 例: "k3F9sP0xYz1Qw8ErT6uVbN4mC2jH7L0"
}
}
Javaここでの重要ポイントは二つです。
一つ目は、「SecureRandom を毎回 new しないで、static フィールドとして 1 個だけ持つ」ことです。SecureRandom は初期化コストがそれなりに高いので、使い回したほうが効率的です。
二つ目は、「CHARSET を自分で決められる」ということです。
英数字だけにするのか、記号も含めるのか、見間違えやすい文字(O と 0、l と 1 など)を除外するのか、といったポリシーを、用途に合わせて設計できます。
実務で使いやすい「ランダム文字列ユーティリティ」の形
用途別にメソッドを分ける
業務コードでは、「用途ごとに少しずつ要件が違う」ことがよくあります。
例えば、次のようなパターンです。
一時パスワード用:英大小文字+数字+記号、長さ 12 以上。
メール認証コード用:数字だけ、長さ 6。
トークン用:英数字のみ、長さ 32、SecureRandom 必須。
これを毎回バラバラに書くのではなく、ユーティリティクラスにまとめておくと、コードの意図がとても読みやすくなります。
import java.security.SecureRandom;
public final class RandomTokens {
private static final String ALPHANUMERIC =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final String DIGITS = "0123456789";
private static final String PASSWORD_CHARS =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private RandomTokens() {}
public static String authCode6Digits() {
return randomFromCharset(DIGITS, 6);
}
public static String apiToken32() {
return randomFromCharset(ALPHANUMERIC, 32);
}
public static String tempPassword12() {
return randomFromCharset(PASSWORD_CHARS, 12);
}
public static String randomFromCharset(String charset, int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int index = SECURE_RANDOM.nextInt(charset.length());
sb.append(charset.charAt(index));
}
return sb.toString();
}
}
Java呼び出し側は、用途に応じてメソッド名だけ見れば意図が分かります。
String code = RandomTokens.authCode6Digits(); // 認証コード
String token = RandomTokens.apiToken32(); // API トークン
String pass = RandomTokens.tempPassword12(); // 一時パスワード
Javaここで深掘りしておきたいのは、「用途ごとにルールを固定しておくと、後から仕様を変えやすい」という点です。
例えば「一時パスワードは記号をやめて英数字だけにしたい」となったとき、PASSWORD_CHARS を変えるだけで済みます。
呼び出し側のコードは一切触らなくてよいので、影響範囲が小さく、レビューもしやすくなります。
UUID を使った「なんちゃってランダム文字列」という選択肢
UUID をそのまま使う簡易パターン
「とにかく一意っぽい文字列が欲しいだけで、英数字だけでなくてもいい」という場合、UUID をそのまま使うのも実務ではよくあります。
import java.util.UUID;
public class UuidBasedRandom {
public static String uuidString() {
return UUID.randomUUID().toString(); // 例: "550e8400-e29b-41d4-a716-446655440000"
}
public static String uuidCompact() {
return UUID.randomUUID().toString().replace("-", ""); // 32 桁
}
}
JavaUUID は内部的に暗号学的に強い乱数を使う実装が多く、「かなり高い確率で一意な文字列」を簡単に得られます。
ただし、形式が固定(16進数+ハイフン)で長さも決まっているので、「桁数を自由に変えたい」「文字種を制御したい」といった用途には向きません。
UUID と SecureRandom の使い分け
ざっくり言うと、次のような感覚で使い分けるとよいです。
「ID として一意性が欲しいだけ」なら UUID。
「パスワードや認証コードなど、形式や長さを細かく制御したい」なら SecureRandom+自前の文字セット。
UUID は「一意性担当」、SecureRandom+文字セットは「形式と安全性担当」とイメージすると、設計の整理がしやすくなります。
ランダム文字列生成で気をつけたいポイント
Random と SecureRandom を混同しない
一番大事なのは、「セキュリティが絡むところで Random を使わない」ということです。Random はテストデータや単なるシャッフルには便利ですが、攻撃者に観測される可能性がある場面では危険です。
一時パスワード、トークン、セッションID、認証コードなど、「破られると困るもの」は、必ず SecureRandom ベースの実装にしておきましょう。
文字セットと長さは「用途から逆算」する
「とりあえず 8 桁でいいか」と適当に決めるのではなく、「何回試行されたら危ないか」「どれくらいの期間有効か」といった観点から、必要な強度を考えるのが本来の姿です。
初心者のうちは、まずは「一時パスワードなら 12〜16 文字程度」「トークンなら 32 文字以上」といった、少し余裕のある設定にしておくとよいです。
また、ユーザーが手入力するコード(SMS 認証コードなど)は、数字だけ・6 桁程度にしておくと、入力ミスが減って UX が良くなります。
逆に、ユーザーが直接触らないトークンは、多少長くても問題ありません。
まとめ:初心者がランダム文字列生成で身につけるべき感覚
ランダム文字列生成は、「ただランダムに見えればいい」のではなく、「用途に合った安全性と扱いやすさを持った文字列を設計する」作業です。
まずは、Random と SecureRandom の違いを理解し、「セキュリティが絡むところでは SecureRandom 一択」と体に刻む。
次に、「使う文字セット」と「長さ」を用途から逆算し、それをユーティリティクラスに閉じ込めて、呼び出し側はメソッド名だけで意図が分かるようにする。
UUID は「一意な ID が欲しいだけ」の場面での簡易な選択肢として覚えておく。
ここまで押さえれば、「とりあえず適当にランダムっぽい文字列を作る」段階から一歩抜け出せます。

