安全な乱数の作り方。CSPRNGでトークンや一時URLを予測されない値にする
対象の目安: Webアプリ開発者と設計担当 / 実務

パスワードリセットのURLに付くトークン、招待リンクのキー、APIキー、ダウンロード用の一時URL。これらはどれも「その値を知っている人だけが正当な利用者である」という前提で権限を与えています。前提が成り立つのは、値が第三者に推測できないときだけです。生成に使った乱数が予測可能だと、認証も認可も通さずに、値を計算するだけで他人の権限が手に入ります。
やっかいなのは、この欠陥がテストで見つかりにくいことです。Math.random()で作ったトークンも、secrets.token_urlsafe()で作ったトークンも、見た目はただのランダムな文字列で、機能テストはどちらも通ります。違いが表に出るのは、攻撃者が出力をいくつか集めて内部状態を解いたときだけです。
この記事は、一般用途の擬似乱数がなぜ推測されうるのかという機構から始めて、暗号論的擬似乱数生成器(CSPRNG)への置き換え、必要なビット数の見積もり方、言語別の正しい書き方、生成した値をその後どう扱うかまでを、MITREのCWEとOWASPとNISTと各言語の公式ドキュメントで確認できた範囲で整理します。対象はWebアプリの開発者と設計担当です。
予測できる乱数がどこで権限に変わるのか
擬似乱数生成器は、内部状態を持ち、決められた手順でその状態を更新しながら数値を出力する仕組みです。真の乱数ではなく計算です。同じ内部状態から始めれば、何度実行しても同じ列が出ます。この性質は再現性が欲しい場面では利点ですが、秘密の値を作る場面では欠陥になります。
MITREはこの欠陥をCWE-338「Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)」として登録しています。説明は、暗号強度を持たないアルゴリズムのPRNGをセキュリティ上の文脈で使うこと、とされています。影響については、弱いPRNGが認証トークンや暗号鍵の生成に使われた場合、攻撃者はIDや鍵を容易に推測して制限された機能へアクセスできる、と書かれています。CWE-338の親にあたるCWE-330「Use of Insufficiently Random Values」は、PRNGを統計用途と暗号用途の2種類に分け、統計用途のものは出力が予測可能でセキュリティには適さない、と整理しています。
具体例を言語の実装で見ると、抽象論ではないことが分かります。V8のブログは、Math.random()の実装をxorshift128+に置き換えた経緯を説明し、この生成器は128ビットの内部状態を持つと述べたうえで、MWC1616からの大きな改善ではあるが依然として暗号論的に安全ではないと明記しています。同記事はハッシュや署名生成、暗号化と復号のような用途に通常のPRNGは適さないとし、window.crypto.getRandomValuesを使うよう案内しています。MDNもMath.random()について、暗号論的に安全な乱数を提供しないため、セキュリティに関わるものには使わず、Web Crypto APIのCrypto.getRandomValues()を使うようにと書いています。
Pythonのrandomモジュールも同じ位置づけです。公式ドキュメントは、このモジュールの擬似乱数生成器はセキュリティ目的に使うべきではなく、セキュリティや暗号用途にはsecretsモジュールを参照するよう警告しています。PHPのmt_rand()のマニュアルにはさらに強い注意書きがあり、この関数は暗号論的に安全な値を生成せず、暗号用途や、返り値が推測不能であることを要する用途に使ってはならない、とされています。
要点は「乱数の質がなんとなく低い」ことではありません。内部状態の大きさが有限で、出力から状態を復元する手順が知られているという構造上の性質です。状態が分かれば、次に出る値も、過去にさかのぼって出た値も計算できます。攻撃者が同じサービスで自分用のトークンを何度か発行させるだけで観測サンプルが集まる、という点も見落とされがちです。
CSPRNGが満たしている条件
暗号論的擬似乱数生成器(CSPRNG)も内部状態を持つ決定的なアルゴリズムである点は同じです。違いは、出力から内部状態を復元することが計算量的に困難になるよう設計されている点にあります。CWE-330は、セキュリティに依存する値は暗号論的に安全でなければならず、攻撃者が真の乱数と区別することがほぼ不可能である必要がある、と述べています。
OWASPのCryptographic Storage Cheat Sheetは、この2種類を並べて説明しています。PRNGは低品質だが高速で、ページ上の並び替えやUI要素のランダム化のようなセキュリティに関係しない機能には使えるものの、セキュリティ上重要なものには使ってはならない、としています。CSPRNGはより高い品質のランダム性(より厳密には、より多くのエントロピー)を生み出すよう設計されており、セキュリティに関わる機能に安全に使える一方、遅く、CPU負荷が高く、大量の乱数を要求すると状況によってはブロックしうる、とも書かれています。
米国の標準側では、この領域はNISTのSP 800-90シリーズが扱っています。SP 800-90A Rev. 1は「Recommendation for Random Number Generation Using Deterministic Random Bit Generators」(2015年6月)で、ハッシュ関数またはブロック暗号アルゴリズムにもとづく決定的な乱数ビット生成の仕組み、つまりDRBGを規定しています。SP 800-90Bは「Recommendation for the Entropy Sources Used for Random Bit Generation」(2018年1月)で、乱数ビット生成に使うエントロピー源の設計原則と要件、および検証試験を定めています。DRBGは種となるエントロピーから乱数列を伸ばす部分、エントロピー源はその種を供給する部分という役割分担です。
アプリケーション開発者がこれらを直接実装することはまずありません。実際に触れるのはOSと標準ライブラリが提供する入口で、その裏側でOSがエントロピー源とDRBGを組み合わせています。Goのcrypto/randの公式ドキュメントは、ReaderがLinuxとFreeBSDとDragonflyとSolarisではgetrandom(2)、macOSとiOSとOpenBSDではarc4random_buf(3)、WindowsではProcessPrng APIを使うと明記しており、FIPS 140-3モードでは出力がSP 800-90A Rev. 1のDRBGを通ると書いています。PHPのrandom_bytes()のマニュアルも、Linuxではgetrandom()や/dev/urandom、Windowsでは CNG API といった順でOSの乱数源を使うと列挙しています。
乱数の品質を要求する値としない値
どこまでをCSPRNGで作るべきかは、「その値を当てられたら何が起きるか」で決めます。値を知ることが権限や資源へのアクセスに直結するなら、CSPRNGの対象です。
| 用途 | 当てられたときに起きること | 生成方法 |
|---|---|---|
| セッションID | 認証を経ずに本人になりすまされる | CSPRNG |
| パスワードリセットトークン | 任意アカウントのパスワードを再設定される | CSPRNG |
| 招待URLや共有URLのキー | 招待されていない相手が対象資源へ入る | CSPRNG |
| CSRFトークン | クロスサイトからの不正操作が通る | CSPRNG |
| APIキーやクライアントシークレット | API経由で権限を行使される | CSPRNG |
| 一時パスワードや有効化コード | 初回ログインを乗っ取られる | CSPRNG |
| 公開ディレクトリ上のアップロードファイル名 | 他人のアップロードを列挙して読まれる | CSPRNG |
| 暗号鍵やIVやソルト | 暗号の前提が崩れる | CSPRNG |
| 一覧のシャッフル表示やA/Bテストの割り当て | 表示順が読まれるだけ | 一般用途のPRNGでよい |
CWE-330は、予測可能な識別子によって攻撃者が他の利用者の資源を推測したり、先回りして作成したりできる状態を、リソースの乗っ取りとして挙げています。ファイル名や連番IDのような「秘密のつもりがなかった値」が権限の代わりに働いてしまう構図は、この形で起きます。
セッションIDについては、OWASPのSession Management Cheat Sheetが具体的な数値を示しています。総当たりによる推測を防ぐためセッション識別子は少なくとも64ビットのエントロピーを持たなければならず、生成には強力なCSPRNGを使わなければならない、としています。さらに、自分でセッションIDを作る必要がある場合はCSPRNGを使い、サイズは少なくとも128ビットとし、各セッションIDが一意であることを保証するようにと書いています。Cookie属性や再生成といったセッション固有の設計は次の記事で扱っています。
あわせて読みたい
セッション管理とセッションハイジャック対策。Cookie属性とセッションID再生成で不正利用を防ぐ設計
何ビット必要かの見積もり
長さの議論は、文字数ではなくエントロピーのビット数で行います。エントロピーは実質的な当てにくさの尺度で、1ビット増えるごとに候補数が2倍になります。
現行の基準として明確なのはOWASP ASVSです。v5.0.0のV11.5.1は、推測されてはならないことを意図したすべての乱数と文字列は、CSPRNGで生成され、少なくとも128ビットのエントロピーを持つことを検証せよ、と求めています。同じ要件には、UUIDはこの条件を満たさない、という注記が付いています。V11.5.2は、乱数生成の仕組みが高負荷時でも安全に動作するよう設計されていることを求めています。
言語の公式ドキュメント側にも同じ水準の記述があります。Goのcrypto/randのText関数(Go 1.24で追加)は、秘密の文字列やトークン、パスワードなどのテキストが必要なときに使うRFC 4648標準base32アルファベットのランダム文字列を返すもので、結果は少なくとも128ビットのランダム性を含み、総当たり推測を防ぎ衝突の可能性を極めて小さくするのに十分だ、と説明されています。Pythonのsecretsモジュールのドキュメントは、トークンに必要な量は計算機の性能向上とともに増えるとしたうえで、2015年時点では32バイト(256ビット)のランダム性がこのモジュールの想定する典型的な用途に十分だと考えられている、と述べています。
実装で扱うのはバイト数と文字数なので、対応関係を押さえておくと迷いません。
| 乱数バイト数 | エントロピー | 16進表記の文字数 | base64url表記の文字数(パディングなし) |
|---|---|---|---|
| 16バイト | 128ビット | 32文字 | 22文字 |
| 24バイト | 192ビット | 48文字 | 32文字 |
| 32バイト | 256ビット | 64文字 | 43文字 |
16バイトを下限、32バイトを既定値として選んでおけば、ASVSの128ビットとPythonのドキュメントが挙げる256ビットの両方を満たせます。エンコードは値の見た目を変えるだけで、エントロピーを増やしません。トークンが64文字あっても、乱数由来が8バイト分しかなければ実質は64ビットのままです。
数字だけや英小文字だけの短いコードは、この計算に照らすと桁が足りません。6桁の数字は候補が10の6乗、およそ20ビット相当です。手入力を前提としたPINや確認コードでこの長さを選ぶ場面はありますが、その場合はエントロピーではなく試行回数の制限で守る設計になります。URLに載せるトークンとメールやSMSで送るコードは、要件が別物として扱います。
注意
文字集合を絞ったランダム文字列を自作するときは、エントロピーが「log2(文字種) × 長さ」で決まる点を計算してから長さを決めます。読み間違えやすい文字を除いた32種類のアルファベットなら1文字あたり5ビットで、128ビットには26文字が必要になります。
言語別の正しい書き方
OWASPのCryptographic Storage Cheat Sheetは、言語ごとに「使ってはならない関数」と「暗号論的に安全な関数」を対応表で並べています。ここではその表と各言語の公式ドキュメントに沿って、誤りと正しい書き方を対比します。
Node.jsではMath.random()が不可で、crypto.randomBytes()とcrypto.randomInt()とcrypto.randomUUID()が安全な関数として挙げられています。公式ドキュメントはcrypto.randomBytes()について、暗号論的に強い擬似乱数データを生成すると説明しています。
// 誤り: Math.random は暗号用途ではない(内部状態から次の出力が決まる)
const token = Math.random().toString(36).slice(2);
// 正しい: 32バイト(256ビット)をCSPRNGから取り、base64urlで文字列化する
import { randomBytes } from "node:crypto";
const token = randomBytes(32).toString("base64url");
Pythonではrandomが不可で、secretsが安全なモジュールです。公式ドキュメントは、secretsはパスワードやアカウント認証、セキュリティトークンなどの管理に適した暗号論的に強い乱数を生成するためのもので、モデリングとシミュレーション向けに設計されたrandomモジュールの既定の擬似乱数生成器よりも優先して使うべきだ、と述べています。
# 誤り: random はモデリングとシミュレーション向け
import random, string
token = "".join(random.choices(string.ascii_letters + string.digits, k=32))
# 正しい: secrets で32バイト分のURL安全なトークンを作る
import secrets
token = secrets.token_urlsafe(32)
JavaではMath.random()とjava.util.RandomとThreadLocalRandomなどが不可で、java.security.SecureRandomとjava.util.UUID.randomUUID()が安全な関数です。SecureRandomの公式APIドキュメントは、このクラスが暗号論的に強い乱数生成器を提供すること、非決定的な出力を生成しなければならないこと、渡すシード材料は予測不能でなければならないことを説明しています。あわせて、実装によってはgenerateSeedやreseedやnextBytesがエントロピー収集のためにブロックしうる、という注記もあります。
// 誤り: 時刻をシードにした java.util.Random は列を再現できる
Random random = new Random(System.currentTimeMillis());
int accountId = random.nextInt();
// 正しい: SecureRandom から32バイト取り出す
SecureRandom rng = new SecureRandom();
byte[] buf = new byte[32];
rng.nextBytes(buf);
String token = Base64.getUrlEncoder().withoutPadding().encodeToString(buf);
PHPではrand()とmt_rand()とuniqid()とlcg_value()とarray_rand()が不可で、random_bytes()とrandom_int()、PHP 8.2以降ではRandom\Engine\Secureが安全な関数です。random_bytes()のマニュアルは、この関数が生成するランダム性は暗号鍵のような長期の秘密の生成を含むすべての用途に適している、と述べています。
// 誤り: mt_rand と uniqid はいずれも推測不能性を保証しない
$token = md5(uniqid(mt_rand(), true));
// 正しい: random_bytes で32バイト取り、16進で64文字にする
$token = bin2hex(random_bytes(32));
Goではmath/randが不可で、crypto/randが安全なパッケージです。Readは暗号論的に安全なランダムバイトでバッファを満たし、エラーを返さず常にバッファ全体を満たす、と公式ドキュメントに書かれています。エラーが返った場合はプログラムを回復不能にクラッシュさせる設計であることも明記されています。
// 誤り: math/rand はシミュレーション向け
token := strconv.FormatInt(mathrand.Int63(), 36)
// 正しい: crypto/rand。Go 1.24 以降は rand.Text() が128ビット以上を返す
token := rand.Text()
// バイト列が必要な場合(エラー処理は不要)
buf := make([]byte, 32)
rand.Read(buf)
Rubyではrand()とRandomが不可で、SecureRandomが安全なライブラリです。公式ドキュメントは、HTTP Cookieのセッションキーの生成などに適した安全な乱数生成器へのインタフェースだと説明しています。
# 誤り: Kernel#rand は暗号用途ではない
token = Array.new(32) { rand(36).to_s(36) }.join
# 正しい: SecureRandom に長さをバイト数で明示する
require "securerandom"
token = SecureRandom.urlsafe_base64(32)
生成した値をその後どう扱うか
CSPRNGで作った時点では、値はまだ「強いパスワード」と同じ状態です。守り方も同じ発想になります。
トークンを発行してから失効させるまで
- 1
CSPRNGで16バイト以上を生成する
生成の直後に、そのまま利用者へ渡す平文の値を確定させる。 - 2
保管用にハッシュ化する
データベースには平文ではなくハッシュ値を保存する。トークン自体が高エントロピーの乱数であれば、パスワード向けの低速ハッシュではなくSHA-256などの高速ハッシュで足りる。 - 3
有効期限と単回使用を付ける
発行時刻からの絶対期限と、使用済みフラグまたは使用時刻を持たせ、1回使われたら失効させる。 - 4
照合を定数時間比較で行う
受け取った値をハッシュ化し、保存済みのハッシュと定数時間比較する。 - 5
失効の経路を用意する
パスワード変更や退会、権限剥奪の契機で、関連するトークンをまとめて無効化できるようにする。
保管をハッシュにする理由は、データベースが読まれた時点で平文のトークンはそのまま権限として使えるからです。ハッシュにしておけば、漏えいしても即座には使えません。パスワードと違って高エントロピーの乱数なので、ストレッチングの必要はありません。パスワードの保管でなぜ低速ハッシュが要るのかという話は、前提が違うため別記事で扱っています。
あわせて読みたい
パスワードはどう保存すべきか。ハッシュ化とソルトとストレッチングの基礎
定数時間比較は、比較処理の所要時間の差から正解の先頭何バイトが一致したかを推し量られる経路を塞ぐための手当てです。各言語に専用の関数があります。Node.jsのcrypto.timingSafeEqualはダイジェストや署名の比較に使い、タイミング攻撃を防ぐためのものだと公式ドキュメントに書かれています。Pythonのsecrets.compare_digestも、タイミング攻撃のリスクを減らすために定数時間比較を使って等しいかを返す、と説明されています。PHPにはhash_equals()、Goにはcrypto/subtleのConstantTimeCompareがあります。
| 言語 | 定数時間比較 |
|---|---|
| Node.js | crypto.timingSafeEqual(a, b) |
| Python | secrets.compare_digest(a, b) |
| PHP | hash_equals($known, $user) |
| Go | subtle.ConstantTimeCompare(a, b) == 1 |
| Java | MessageDigest.isEqual(a, b) |
有効期限と単回使用は、値が漏れる経路を前提にした設計です。URLに載せたトークンはブラウザ履歴やリファラ、プロキシやアクセスログに残ります。期限を短くし、1回使ったら失効させることで、残った痕跡が後から効かないようにします。パスワードリセットのフローで、この設計をどう組むかは個別記事で詳しく扱っています。
あわせて読みたい
パスワード再設定フローの安全な設計。トークンと応答と復旧経路の要件を一次情報で整理
乱数まわりで踏みやすい落とし穴
生成関数を正しく選んでも、周辺の扱いで台無しになる形がいくつかあります。
シードを固定する書き方は、その代表です。MITREはCWE-337「Predictable Seed in Pseudo-Random Number Generator (PRNG)」で、プロセスIDやシステム時刻のような予測可能なシードでPRNGを初期化することを弱点として登録し、予測可能なシードは攻撃者が試すべきシードの数を大きく減らすと説明しています。テストで再現性を得るためにシードを固定したコードが、そのまま本番の生成経路に残る形が起きがちです。CSPRNGを使う場合、シードの管理はOSと標準ライブラリに任せ、アプリケーション側でシードを与えないのが基本です。
同じ根を持つのが、プロセスの複製やイメージの複製にまつわる問題です。自前でシードした利用者空間のPRNGは、状態ごとコピーされれば複製先で同じ列を返します。OSが提供する入口を毎回呼ぶ実装なら、この経路は避けられます。起動直後のエントロピーについては、Linuxのgetrandom(2)のマニュアルに、urandom源がまだ初期化されていない場合、GRND_NONBLOCKが指定されていない限りgetrandom()はブロックすると書かれています。つまりOSの入口を素直に使う限り、初期化前の弱い状態から乱数を取ってしまうことは防がれます。ここでGRND_NONBLOCK相当の非ブロック動作を選んだり、ライブラリ側で独自のフォールバックを持ったりすると、その保護が外れます。
UUIDv4を万能のトークンとして使う設計にも注意が要ります。OWASPのCryptographic Storage Cheat Sheetは、バージョン1のUUIDは高精度のタイムスタンプと生成システムのMACアドレスから成るためランダムではなく、タイプ4のUUIDはランダムに生成されるものの、それがCSPRNGで行われるかは実装依存であり、その言語やフレームワークで安全だと分かっていない限りUUIDのランダム性に依存すべきではない、としています。RFC 9562は、UUIDv4の乱数部を厳密に必要なビット数だけ生成する場合は合計122ビットになると規定し、6.9節で実装はCSPRNGを使うべきだ(SHOULD)と述べています。ASVS 11.5.1が128ビットを求めたうえでUUIDはこの条件を満たさないと注記しているのは、この122ビットという値と対応します。
実装が明示されている場合は話が別です。Node.jsのcrypto.randomUUID()は、RFC 4122 バージョン4のランダムUUIDを生成し、ランダムバイトはWeb Crypto APIのgetRandomValues()で生成されると公式ドキュメントに書かれています。使う関数のドキュメントに乱数源が明記されているかどうかで判断が変わります。
最後の落とし穴が、推測されにくさを自作することです。時刻とユーザーIDとハッシュを組み合わせて長い文字列を作る実装は、見た目のランダム性が高くても、入力側の実質的な自由度しかエントロピーを持ちません。時刻が秒単位でユーザーIDが既知なら、候補は総当たりできる範囲に収まります。CWE-330は、専門家によって現在強いと考えられている十分に検証されたアルゴリズムを使うことを緩和策として挙げています。標準ライブラリの1行に置き換えるのが、この項目に対する答えになります。
生成した鍵やAPIキーをどこに保管するかは、乱数の話とは別の設計になります。値の保管と配布については別記事で整理しています。
あわせて読みたい
シークレット管理の実務。APIキー・認証情報をハードコードせず、Vaultやマネージドサービスで守りローテーションする
コードベースを点検する
既存のコードから弱い生成経路を洗い出すときは、関数名で当たりを付けてから用途を確認します。ヒットしたものすべてが問題ではなく、その値が権限に変わるかどうかで切り分けます。
弱い乱数の使用箇所を洗い出す手順
- 1
危険な関数名で全文検索する
Math.random、java.util.Random、mt_rand、rand()、uniqid、array_rand、math/rand、Kernel#rand、random.choice といったOWASPの表にある関数名を検索する。 - 2
ヒット箇所の値の行き先を追う
画面の表示順やテストデータであれば問題なし。トークン、ID、鍵、ファイル名、パスワードに使われていれば要修正とする。 - 3
シードを与えている箇所を確認する
seed、srand、setSeed、new Random( に引数がある箇所を探し、本番経路に固定シードが残っていないか確かめる。 - 4
生成されている長さを数える
バイト数がそのままエントロピーになる。16バイト未満の生成があれば、根拠を確認する。 - 5
静的解析ルールを常時化する
CI上の静的解析でCWE-330とCWE-338に対応するルールを有効にし、再発をコミット時点で止める。
レビューで見る箇所も同じ観点で絞れます。
乱数生成のレビュー観点
- 推測されては困る値が、その言語のCSPRNG(crypto.randomBytes、secrets、SecureRandom、random_bytes、crypto/rand、SecureRandom)で生成されているか
- 生成しているランダムバイト数が16バイト(128ビット)以上か
- 文字集合を絞ったコードを使う場合、エントロピーを計算したうえで試行回数の制限を併用しているか
- アプリケーション側でシードを固定していないか。テスト用のシード設定が本番経路に残っていないか
- UUIDをトークン代わりに使う場合、その実装の乱数源が公式ドキュメントで確認できているか
- 時刻や連番やユーザーIDを混ぜた自作の生成ロジックになっていないか
- 発行したトークンをハッシュ化して保管しているか
- 照合が定数時間比較になっているか
- 有効期限と単回使用が実装され、期限切れと使用済みが区別して扱われているか
- トークンがURLやログに残る経路を把握し、期限の設定に反映しているか
判断に迷ったときに戻る三つの問い
乱数の設計で確認することは、突き詰めると三つに収まります。
一つ目は、その値を当てられたときに何が起きるかです。権限や資源へのアクセスに直結するなら、生成はCSPRNGの一択になります。表示順やテストデータのように、当てられても何も起きない値は対象外です。
二つ目は、ランダムな入力が何バイトかです。エンコード後の文字数ではなく、生成関数に渡したバイト数がエントロピーを決めます。ASVS v5.0.0は128ビット以上を求めており、16バイトが下限、32バイトが無難な既定値になります。
三つ目は、生成したあとの扱いが値の性質に見合っているかです。高エントロピーの秘密として、ハッシュ化して保管し、定数時間比較で照合し、期限と単回使用で寿命を区切ります。
いずれの答えも、標準ライブラリの1行と、保管や比較の定型に置き換えるだけで実現できます。乱数は自分で工夫する領域ではなく、正しい入口を選んで残りは定型どおりに扱う領域だと考えておくのが、この分野で足を取られないための足場になります。
出典・参考
- CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
- CWE-330: Use of Insufficiently Random Values
- OWASP Cryptographic Storage Cheat Sheet (Secure Random Number Generation)
- OWASP ASVS v5.0.0 V11 Cryptography
- NIST SP 800-90A Rev. 1 Recommendation for Random Number Generation Using Deterministic Random Bit Generators
- NIST SP 800-90B Recommendation for the Entropy Sources Used for Random Bit Generation
関連する記事
セッション管理とセッションハイジャック対策。Cookie属性とセッションID再生成で不正利用を防ぐ設計
WebアプリのセッションIDを安全に扱う設計を、生成のエントロピー、HttpOnlyやSecureなどのCookie属性、ログイン時の再生成、寿命管理まで、なぜその設定が効くのかという機構から実務目線で整理します。
パスワード再設定フローの安全な設計。トークンと応答と復旧経路の要件を一次情報で整理
ログインを多要素認証で固めても、パスワード再設定と復旧の経路が弱ければアカウントはそちらから奪われます。OWASPのForgot Password Cheat SheetとNIST SP 800-63B-4(2025年7月)、ASVS 5.0.0、CWE-640、IPA「安全なウェブサイトの作り方」をもとに、トークンの生成と保管、ユーザー列挙を防ぐ応答、再設定後のセッション処理、復旧経路の選び方、ヘルプデスク経由の統制、実装とテストまで整理します。
シークレット管理の実務。APIキー・認証情報をハードコードせず、Vaultやマネージドサービスで守りローテーションする
APIキーやDB認証情報などのシークレットを、ハードコード回避・集中管理・ローテーション・最小権限という4つの軸で守る方法を、Vaultやクラウドのマネージドサービス、動的シークレットまで実務目線で解説します。


