クライアントサイドバンドルにおける秘密情報スキャンの実際 – ソースコードだけでなくビルドアーティファクトを対象に
問題
フロントエンドアプリケーションでは、環境変数や設定ファイルにAPIキーなどの秘密情報を埋め込むことがあります。ビルド時にこれらの値がクライアントサイドバンドル(JavaScript、CSS、静的アセット)に平文で残ると、ソースコードレベルでの秘密情報検出では見逃され、実際に公開されたアセットから漏洩リスクが発生します。
メカニズム
KeyDriftは、ビルドアーティファクトを直接スキャン対象とし、以下の手順で秘密情報と正当な公開キーを区別します。
-
アーティファクト収集
ビルド出力ディレクトリ(例:dist/,build/)からすべてのファイルをリストアップし、バイナリや圧縮ファイルは除外します。 -
パターンマッチング
環境変数プレフィックス(NEXT_PUBLIC_,VITE_,REACT_APP_など)や、一般的な秘密情報フォーマット(Base64エンコードされた文字列、hex文字列、JWT等)にマッチするトークンを抽出します。 -
コンテキスト判定
抽出したトークンがソースコード内で宣言されているか、あるいはビルド時にのみ注入されているかを、ソースマップやビルドログを参照して判定します。宣言されていないにもかかわらずバンドルに存在する場合は、潜在的な漏洩としてフラグ付けします。 -
公開キーの除外
公開鍵形式(例:-----BEGIN PUBLIC KEY-----)や、既知のパッケージマニフェストに記載されているキーは、正当な公開情報として除外します。
例
次のようなNEXT_PUBLIC_API_KEYが.env.localに定義されているとします。
NEXT_PUBLIC_API_KEY=abcd1234efgh5678ijkl9012mnop3456
Next.jsアプリをnext buildでビルドすると、出力された.next/static/chunks/pages/_app.js内に平文で同じ文字列が現れます。
# KeyDriftのスキャン実行(仮想コマンド)
keydrift scan --dir .next
出力例:
[WARN] Potential secret leak: NEXT_PUBLIC_API_KEY=abcd1234efgh5678ijkl9012mnop3456
File: .next/static/chunks/pages/_app.js:842
Reason: Token matches NEXT_PUBLIC_ prefix but not declared in source.
これにより、ソースコードだけでは検出できなかったビルド時の秘密情報露出を指摘できます。
注意点
-
ソースマップの有無
ソースマップが削除されている本番ビルドでは、宣言元のトレースが困難になるため、ビルドログや環境変数定義ファイルを参照する仕組みが必要です。 -
偽陽性の可能性
ランタイムで動的に生成されるトークン(例: 認証トークン)は、一時的にバンドル内に現れることがあります。これらはコンテキスト判定で除外するか、スキャン対象のビルドタイプ(開発vs本番)を明確に分けることで精度を向上させます。 -
スキャン範囲の調整
大規模なモノレポでは、対象とするビルドアーティファクトのディレクトリを限定し、不必要なスキャンコストを避けるように設定します。
English summary: See https://keydrift.dev/handbook?utm_source=qiita&utm_campaign=socialhat&utm_medium=social&vsr=71f36de66a45467a3b6a for details.