システム開発をしていると、550e8400-e29b-41d4-a716-446655440000 や eyJhbGciOiJIUzI1NiJ9... のような「ランダムっぽい文字列」に頻繁に出会います。UUID、パスワード、ハッシュ、トークン、API キー……見た目はどれも似ていますが、設計思想と用途はまったく違います。
この記事では、開発現場でよく使われる 8 種類のランダム風文字列を「なぜ存在するのか」「何を守るのか」という視点で整理します。それぞれの正体を理解すれば、「どの場面でどれを使うべきか」が自然と判断できるようになります。
8 種類の比較一覧
まず、全体像をつかむために一覧表を見てみましょう。
| 種類 | 主な用途 | 秘密性 | 可逆性 | 生成方法 | 特徴 |
|---|---|---|---|---|---|
| UUID | 一意な識別 | 不要 | — | ランダム / 時刻 | 衝突しない ID |
| パスワード | 本人認証 | 必須 | 本人のみ | 人間が作成 | 記憶前提の秘密 |
| ハッシュ | 同一性の検証 | 不要 | 不可逆 | 数学関数 | デジタル指紋 |
| トークン | 認証・認可 | 必須 | 場合による | 暗号乱数 | 有効期限つき |
| API キー | サービス認証 | 必須 | — | 暗号乱数 | 機械用パスワード |
| Salt | ハッシュ強化 | 不要 | — | 暗号乱数 | レインボーテーブル対策 |
| Nonce | 一回限りの識別 | 不要 | — | 暗号乱数 | リプレイ攻撃防止 |
| Signature | 改ざん検知 | 不要 | 不可逆 | 暗号計算 | HMAC, RSA 署名 |
ポイントは、見た目ではなく「設計目的」で分類することです。同じ 32 文字のランダム文字列でも、UUID として使えばただの名札、トークンとして使えば認証の鍵になります。
UUID — 衝突しない名札
UUID(Universally Unique Identifier)は、「世界中で重複しない ID を生成する」ための仕組みです。セキュリティとは直接関係がなく、あくまで識別が目的です。
もっとも広く使われる UUID v4 はランダム生成で、122 ビットのエントロピーを持ちます。これは約 5.3 × 1036 通り ―― 1 秒に 10 億個生成しても、衝突するまで 100 億年以上かかる計算です。
よく使われる場面:
- データベースの主キー(auto increment の代替)
- 分散システムでの一意なオブジェクト ID
- ファイル名の衝突回避(アップロード時など)
- トラッキング用のリクエスト ID
UUID v1 はタイムスタンプと MAC アドレスを含むため、生成時刻や端末が推測可能です。外部に公開する ID には v4(完全ランダム)を使いましょう。また、UUID をそのままセッションキーやトークンに流用するのはアンチパターンです。UUID は「ぶつからない」ことは保証しますが、「推測されない」ことは保証しません。
パスワード — 人間が扱う唯一の秘密
パスワードは、この 8 種類の中で唯一「人間が記憶する」ことを前提に設計されています。そのため、エントロピー(ランダム性)は人間の記憶力に依存し、他の文字列と比べて本質的に弱い存在です。
だからこそ、パスワードの保存にはひと手間が必要です。平文で保存するのは論外で、必ずハッシュ化してから保存します。さらに、単純なハッシュではなく、bcrypt、Argon2、scrypt のような「わざと遅い」アルゴリズムを使うのが現代のベストプラクティスです。
なぜ「遅い」ことが重要なのでしょうか? 攻撃者がブルートフォース(総当たり)で 1 秒に数十億回のハッシュ計算を試みるとき、1 回の計算に 0.1 秒かかるアルゴリズムなら、攻撃コストが桁違いに跳ね上がるからです。
よく使われる場面:
- Web サービスのログイン認証
- SSH、データベースアクセスの認証
- 暗号化ファイルの復号鍵(パスフレーズ)
パスワードの強度は「文字種 × 長さ」で決まります。P@ssw0rd のような「記号を入れただけ」の短いパスワードより、correct horse battery staple のような長いパスフレーズの方が遥かに安全です。パスワードマネージャーの利用を強く推奨します。パスワードマネージャーの利用を強く推奨します。
ハッシュ — デジタル指紋
ハッシュ関数は、任意の長さのデータを固定長の値に変換する一方向関数です。同じ入力からは必ず同じ出力が得られますが、出力から入力を復元することはできません。いわばデータの指紋です。
たとえば、SHA-256 でハッシュすると、「hello」という 5 文字の入力も、1GB のファイルも、どちらも 256 ビット(64 文字の 16 進数)に圧縮されます。元のデータが 1 ビットでも変われば、ハッシュ値はまったく別物になります。
よく使われる場面:
- パスワード保存 — 平文の代わりにハッシュ値を DB に格納する
- ファイルの整合性チェック — ダウンロードしたファイルが改ざんされていないか確認する(チェックサム)
- Git のコミット ID — Git はすべてのコミットを SHA-1 ハッシュで管理している
- ブロックチェーン — 取引データの連鎖をハッシュで保証する
MD5 と SHA-1 は衝突攻撃が現実的に可能なため、セキュリティ用途には使わないでください。新規プロジェクトでは SHA-256 以上を選びましょう。パスワード保存には SHA 系ではなく、前述の bcrypt / Argon2 を使います(SHA は「速すぎる」ため、ブルートフォースに弱い)。
トークン — 有効期限つきの合言葉
トークンは、「この人はログイン済みである」ことを証明する一時的な文字列です。ログインに成功するとサーバーがトークンを発行し、以降のリクエストにはそのトークンを添付して「自分は認証済みです」と主張します。
もっとも有名なのは JWT(JSON Web Token) で、ヘッダー・ペイロード・署名の 3 パートを Base64 エンコードした構造を持ちます。ペイロードにユーザー ID や有効期限が含まれており、署名によって改ざんが検知できます。
よく使われる場面:
- Web アプリのセッション管理
- OAuth 2.0 のアクセストークン / リフレッシュトークン
- メール認証やパスワードリセットのワンタイムリンク
- SPA(Single Page Application)のステートレス認証
JWT はペイロードが Base64 エンコード(暗号化ではない)なので、中身は誰でも読めます。パスワードやクレジットカード番号を JWT に入れてはいけません。また、トークンの有効期限は短く設定し(アクセストークンは 15 分〜1 時間が目安)、リフレッシュトークンで再発行するパターンが安全です。
API キー — 機械のためのパスワード
API キーは、アプリケーションやサービスが「自分は許可された利用者です」と名乗るための文字列です。人間が入力するのではなく、コードに埋め込んでリクエストに添付します。
パスワードとの最大の違いは、人間が覚える必要がないこと。そのため、十分な長さ(128〜256 ビット)のランダム文字列として生成でき、強度は高くなります。一方で、ソースコードや設定ファイルに平文で書かれがちなので、漏洩リスクが高い側面もあります。
よく使われる場面:
- 外部 API(Google Maps, OpenAI, Stripe)の利用認証
- マイクロサービス間の内部通信認証
- 課金やレート制限の識別
API キーを GitHub に push してしまう事故は後を絶ちません。.env ファイルや環境変数に格納し、.gitignore に追加するのは基本中の基本です。GitHub 自体にも「Secret Scanning」機能があり、主要サービスの API キーがコミットされると自動で無効化される仕組みがありますが、頼り切りは危険です。
Salt・Nonce・Signature — 裏方の専門家たち
この 3 つは単独で使われることは少なく、他の仕組みを強化するための部品です。
Salt(ソルト)
パスワードをハッシュ化する際に、ユーザーごとに異なるランダム値を付加するのが Salt です。同じパスワード「password123」を使っている 2 人のユーザーがいても、Salt が違えばハッシュ値は異なります。これにより、事前計算されたハッシュ辞書(レインボーテーブル)を使った攻撃を防ぎます。
Salt 自体は秘密にする必要がなく、ハッシュ値と一緒にデータベースに保存します。bcrypt や Argon2 は内部で自動的に Salt を生成・管理してくれるため、開発者が手動で扱う機会は減っています。
Nonce(ナンス)
Nonce は「Number used ONCE」の略で、一度だけ使う使い捨ての値です。主な目的はリプレイ攻撃の防止。通信を盗聴した攻撃者が同じリクエストをもう一度送信しても、Nonce が使用済みなら無効になります。
Web 開発では、CSRF(クロスサイトリクエストフォージェリ)対策のフォームトークンとしても使われます。WordPress の wp_nonce_field() がまさにこれです。
Signature(署名)
Signature は、データが改ざんされていないことを証明します。HMAC(Hash-based Message Authentication Code)では、秘密鍵とメッセージを組み合わせてハッシュを計算します。秘密鍵を知らない第三者は正しい署名を作れないため、受信者は「このデータは正規の送信者から来た」と確認できます。
JWT のヘッダーに含まれる alg: HS256 は「HMAC-SHA256 で署名する」という意味です。API の Webhook(Stripe, GitHub など)でも、リクエストボディの改ざん検知に HMAC 署名が使われています。
設計軸で整理する
8 種類をバラバラに覚えるのではなく、5 つの軸で整理すると頭に入りやすくなります。
| 種類 | 秘密にする? | 復元できる? | 一意性が命? | 有効期限? | 人間が使う? |
|---|---|---|---|---|---|
| UUID | × | × | ◎ | × | × |
| パスワード | ◎ | ◎(本人のみ) | △ | × | ◎ |
| ハッシュ | × | ×(不可逆) | △ | × | × |
| トークン | ◎ | △ | ◎ | ◎ | × |
| API キー | ◎ | × | ◎ | △ | × |
| Salt | × | × | △ | × | × |
| Nonce | × | × | ◎ | ◎ | × |
| Signature | × | ×(不可逆) | — | — | × |
注目すべきは、パスワードだけが「人間が使う」に◎がつくこと。パスワードが他のすべてと違う特殊な存在であることが、ここからも見て取れます。
攻撃モデルから考える
セキュリティ設計では「何を守るか」ではなく「どんな攻撃を防ぐか」から考えるのが鉄則です。文字列の種類ごとに、想定される攻撃は異なります。
| 種類 | 防ぐべき攻撃 | 対策の考え方 |
|---|---|---|
| UUID | 衝突(ID の重複) | 十分なエントロピーで衝突確率を無視できるレベルに |
| パスワード | ブルートフォース / 辞書攻撃 | 遅いハッシュ + Salt + 長いパスワード |
| ハッシュ | 原像攻撃 / 衝突攻撃 | 安全なアルゴリズム選択(SHA-256 以上) |
| トークン | リプレイ攻撃 / 盗聴 | 短い有効期限 + HTTPS 必須 + リフレッシュ方式 |
| API キー | 漏洩 | 環境変数管理 + ローテーション + IP 制限 |
| Nonce | リプレイ攻撃 | 使い捨て + サーバー側で使用済みチェック |
| Signature | 改ざん | 秘密鍵の厳重管理 + アルゴリズム選択 |
たとえば、UUID の設計で「ブルートフォース耐性」を考慮する必要はありません。逆に、パスワードの設計で「衝突耐性」を気にする場面はほとんどありません。防ぐべき攻撃が違えば、設計判断も変わります。
実務での選び方フロー
「この場面ではどれを使えばいい?」と迷ったときの思考フローです。
- 用途を明確にする — 識別? 認証? 検証? 一時的?
- 防ぐ攻撃を特定する — 衝突? 推測? 漏洩? リプレイ? 改ざん?
- 必要なエントロピーを決める — UUID なら 122 ビット、トークンなら 256 ビット
- 生成方法を選ぶ —
Math.random()は NG、cryptoモジュールを使う - 保存方法を決める — 平文 OK? ハッシュ化? 暗号化? 環境変数?
特に 4 番目は重要です。プログラミング言語の標準的な乱数生成器(Math.random()、random.random())は暗号論的に安全ではありません。セキュリティに関わる文字列の生成には、必ず暗号論的擬似乱数生成器(CSPRNG)を使ってください。Python なら secrets モジュール、Node.js なら crypto.randomBytes() が該当します。
まとめ
8 種類のランダム風文字列を、設計目的で分類すると次の 4 グループになります。
- 識別:UUID
- 認証:パスワード、API キー
- 検証:ハッシュ、Signature
- 一時認証 / 防御:トークン、Nonce、Salt
見た目が同じでも、設計目的がまったく違う ―― これがこの記事の核心です。
開発者として心がけるべきは、「文字列を見るな、用途を見ろ」という原則です。新しいランダム文字列を設計するときも、既存のものを扱うときも、まず「これは何を守るためのものか?」を問うことで、適切な生成方法・保存方法・有効期限が自然と導き出されます。

コメントを残す