Node.jsのUUID生成を極める:crypto.randomUUID() vs 通常のUUID
こんにちは!
今回は、Webフロントで活躍するNode.jsでのUUID生成について、特にcrypto.randomUUID()
と従来の方法の違いを解説します!
はじめに
UUIDは一意の識別子として広く使用されていますが、Node.jsには複数の生成方法があります。
crypto.randomUUID()の使用方法
import { randomUUID } from 'crypto';
const id = randomUUID();
console.log(id); // 例:'123e4567-e89b-12d3-a456-426614174000'
または、以下のように書いてもいいですね
import crypto from 'crypto';
const id= crypto.randomUUID();
主な特徴
- 暗号学的に安全な乱数生成器を使用
- 追加のパッケージインストールが不要
- パフォーマンスが最適化済み
- UUID v4形式を生成
従来のUUID生成方法
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
console.log(id);
特徴
- 複数のUUIDバージョンに対応
- カスタマイズオプションが豊富
- コミュニティでの実績が長い
- NPMパッケージのインストールが必要
複数のUUIDバージョンを使用する場合
import { v1, v3, v4, v5 } from 'uuid';
const timeBasedId = v1(); // タイムベース
const nameBasedMD5Id = v3('hello', v3.DNS); // 名前ベース(MD5)
const randomId = v4(); // ランダム
const nameBasedSHA1Id = v5('hello', v5.DNS); // 名前ベース(SHA-1)
どちらを選ぶべき?
crypto.randomUUID()を選ぶケース
- セキュリティが重要な場合
- 依存関係を最小限に抑えたい場合
- シンプルなUUID v4の生成で十分な場合
uuidパッケージを選ぶケース
- 特定のUUIDバージョンが必要な場合
- 生成プロセスをカスタマイズしたい場合
- 下位バージョンのNode.jsとの互換性が必要な場合
まとめ
プロジェクトの要件に応じて、適切な方法を選択してください。特に理由がない場合は、組み込みのcrypto.randomUUID()
を使用することをお勧めします。
Appendix:暗号学的に安全な乱数とは?
さて、暗号学的に安全な乱数生成器(Cryptographically Secure Random Number Generator: CSPRNG)とは何でしょうか?
「セキュリティ的に良い」だけでは、ちょっと物足りないかもしれませんのでこれについて、Appendixで具体的にみていきましょう。
基本的な特徴
暗号号学的に安全な乱数生成器とは、基本的には以下のような特徴があります
1.予測不可能性
- 生成された乱数の次の値を予測することが実質的に不可能
- これまでの出力からパターンを見つけることができない
2.均一な分布
- すべての可能な値が同じ確率で出現
- 偏りがない
一般的な乱数生成器との違い
例えば、JavaScriptのMath.random()
との比較で見てみましょう:
// 一般的な乱数生成
const normal = Math.random();
// 暗号学的に安全な乱数生成
import { randomBytes } from 'crypto';
const secure = randomBytes(8).readBigUInt64BE() / BigInt(2 ** 64);
Math.random()の問題点
- シード値から次の値が予測可能
- 暗号用途には不適切
- 擬似乱数生成アルゴリズムが比較的単純
crypto.randomUUID()の利点
- OSの提供する暗号学的乱数源を使用(Linux の場合は /dev/urandom など)
- 物理的なノイズソースを利用
- 予測が極めて困難
実際のユースケース
暗号学的に安全な乱数が重要な場面:
- セキュリティトークンの生成
import { randomBytes } from 'crypto';
const secureToken = randomBytes(32).toString('hex');
- パスワードリセットトークン
import { randomUUID } from 'crypto';
const resetToken = randomUUID();
- 初期化ベクトル(IV)の生成
import { randomBytes } from 'crypto';
const iv = randomBytes(16); // AES-256用
実際の違いを視覚化
一般的な乱数生成器と暗号学的に安全な乱数生成器の違いを見てみましょう:
import { randomBytes } from 'crypto';
// 一般的な乱数列
const normalRandoms = Array.from(
{ length: 1000 },
() => Math.random()
);
// 暗号学的に安全な乱数列
const secureRandoms = Array.from(
{ length: 1000 },
() => randomBytes(8).readBigUInt64BE() / BigInt(2 ** 64)
);
一般的な乱数生成器は、短時間で大量の値を生成する必要がある場合に適していますが、予測可能性があるため、セキュリティが重要な用途には適していません。
一方、暗号学的に安全な乱数生成器は:
- より多くのエントロピー(ランダム性)を持つ
- 予測が実質的に不可能
- 計算コストは高いが、セキュリティが保証される
これが、UUIDの生成においてcrypto.randomUUID()
が推奨される理由です。特に認証トークンやセッションIDなど、セキュリティが重要な場面では、この予測不可能性が極めて重要になります。