公開された .env ファイルと漏洩キー

公開された .env ファイルとは、データベースのパスワード、メール認証情報、API キーを保持する設定ファイルが、名前を告げるだけですべての人に Web サーバーから渡されてしまう状態であり、公開された .git フォルダは、ソース履歴全体が付属した同じ事故です。どちらも攻撃者が何かを破る必要はありません。ファイルが単にサーバーが公開する場所に置かれているだけで、通常の GET リクエスト1回でダウンロードできます。この記事では、それがどう起きるか——ドキュメントルートのミス、リポジトリ自体を配信する静的ホスト、誰も監査しなかったビルド成果物——、発見者が最初の1時間にキーで何をするか、そして後からファイルを削除することが対応の中で最も小さな部分である理由を説明します。今すぐ自分のサイトを確認するには、漏洩シークレットスキャナーを実行し、結果と照らして読んでください。

私有ファイルが公開される仕組み:ドキュメントルート

すべての Web サーバーにはドキュメントルートがあります。その内容が定義上公開であるディレクトリです。その中に入れられたものは——意図的であれ偶然であれ——どのページからリンクされていなくても URL でリクエストできます。典型的な事故は、作業ディレクトリ全体をサーバーにコピーしてデプロイするプロジェクトです。本来そこにあるべきアプリケーションコードが、その隣の .env ファイル、その中の .git フォルダ、エディタのバックアップコピー、移行前に誰かが作ったデータベースダンプ、先月のバージョンのアーカイブと一緒に到着します。サーバーはこれらを区別できません。サーバーはファイルを配信するのであり、私有のものもファイルです。

フレームワークの慣習が罠をかかりやすくします。.env ファイルはドキュメントルートの1つ上、あるいはデプロイされるツリーの完全に外に置かれ、アプリケーションは Web サーバー経由ではなくディスクから読むべきものです。しかし開発サーバーは喜んでプロジェクトルートを配信し、小規模なデプロイはすべてを public_html に引きずり込み、チュートリアルからコピーした設定はドキュメントルートをプロジェクト自体に向けるかもしれません。これが起きても目に見えて壊れるものはなく、それこそが問題です。サイトは完璧に動作し、ファイルは公開されており、最初に気づくのは /.env をリクエストした人物——自動スキャナーがインターネット上のすべてのサイトに対して絶え間なく送るリクエスト——です。

静的ホスト、配信されるリポジトリ、ビルド成果物

静的ホスティングはサーバー設定を方程式から外し、より単純なルールに置き換えます。公開ディレクトリにあるものが公開される、というルールです。出力ディレクトリをプロジェクトルートに設定してリポジトリを静的ホストにデプロイすると、ホストはリポジトリを忠実に配信します——出力にコピーされていれば .git も含まれます。公開された .git は見た目より深刻です。HEAD ファイルと設定が構造を証明し、オブジェクトファイルにはコミットされたすべての blob が含まれ、通常の Git ツールで履歴全体を再構築できます——一度コミットされ、後のコミットで「削除」されたシークレットも含まれます。その削除は作業ツリーから取り除くだけで、それ以外のどこからも取り除きません。

ビルド成果物は第二の、より静かな公開のクラスを生みます。JavaScript バンドラーはコードが参照するものをインライン化するため、ビルド時に環境変数から読まれた API キーが、配信されるバンドルの中のリテラル文字列として終わることがあります——設計上公開であり、すべての訪問者が読め、ファイル自体は公開されるべきものだったため、どの権限チェックにも引っかかりません。ソースマップは元のソースをバンドルの隣に出荷することで事態を悪化させます。これらはどれもサーバーの設定ミスを必要としません。必要なのは、外部から一度も検査されなかったビルドだけです。

第三のパターンは残留物です。アーカイブをウェブルートに展開してそのアーカイブをそこに残すデプロイスクリプト、Web からアクセスできるフォルダにダンプを書くバックアッププラグイン、エディタが保存した config.php.bak——多くのサーバーは、拡張子が PHP ハンドラに一致しなくなったからこそ、それを平文として配信します。各残留物は私有なものの完全なコピーであり、予測可能なアドレスにあります。

攻撃者が最初の1時間にすること

発見は自動化され、絶え間なく続きます。スキャナーは広大なアドレス範囲にわたって既知のパス——env ファイル、Git の内部、設定名、バックアップ拡張子——を列挙し、新しい公開は通常数時間以内、しばしばそれより速く見つかります。あなたのサーバーに届くのは 200 を返す何の変哲もない GET リクエストです。サーバーの視点では何も異常なことは起きていないため、アラームはありません。したがって、1日でも公開されていたファイルはダウンロードされたと想定し、立証責任は逆方向に走ると考えてください。

選別も自動化されています。ダウンロードされた .env は数秒で解析されます。データベース認証情報は到達可能なあらゆるデータベースポートで試され、クラウドキーは有効かどうかを告げる無害な API 呼び出しで検証され、メール認証情報は送信に試され、支払いキーはモードが確認されます——ライブモードの支払いキーと本番データベース認証情報は大当たりであり、それぞれが直接お金やデータに換わるためです。有効なキーは、所有者がいつでもローテーションする可能性があるため、素早く使われ、取引され、保持されます。公開されたキーが最も価値を持つのは最初の1時間であり、その時間は効率的に使われます。

ファイルを削除するだけでは不十分な理由

ファイルを削除すると新しいダウンロードは止まります。すでに存在するコピーには何の効果もありません。発見者のコピーは明らかですが、あなた自身が作ったコピーもあります——CDN や企業プロキシにキャッシュされた応答、検索エンジンやアーカイブサービスのクロール内のスナップショット、ブラウザがすでにダウンロードしたバンドルです。すべてのキャッシュが消去され期限切れになるまで、「削除された」ファイルは、あなたが管理しているのに清掃を忘れたインフラから配信され続けるかもしれず、あなたの管理の外にあるバージョンは永久にその外にあります。

だからこそ、確認された公開への最初の対応は削除ではなくローテーションです。公開された認証情報を失効させ、新しいものを発行することで、世界中のすべてのコピーが同じ瞬間に無価値になります。ローテーションには順序があります——代替を発行し、デプロイし、サービスが動作することを確認し、それから古い認証情報を失効させる——そしてそれは公開された材料が開けるすべてのものに及びます。.git の公開は、現在のものだけでなく、履歴に現れたすべてのシークレットをローテーションすることを意味します。開示されたのは履歴そのものだからです。その後、公開されたパスについてアクセスログを読んでください。それはいち早く知ったのがあなたかどうかを教えてくれ、より早い取得は設定インシデントを、まったく異なるチェックリストを持つ侵害調査に変えます。

プローブリストの解説 — そして予防チェックリスト

漏洩シークレットスキャナーのようなスキャナーはファイル名前でしか要求できないため、そのリストは既知の集合です。/.env とその環境変種、/.git/HEAD と /.git/config、馴染みのある設定ファイル名、バックアップとアーカイブの拡張子、キーファイル名——そしてページ自身のスクリプトをキーらしい文字列で検索します。正直な限界は双方向に効きます。スキャナーは要求したものしか見つけられないため、発見はステータスコードではなく内容で確認します。トップページを返す 200 はキャッチオールのルートであり漏洩ではなく、それを漏洩と数えるレポートは自己膨張しています。関連するサプライチェーンリスク——他者から意図的に読み込むスクリプト——はサードパーティスクリプトとサプライチェーンリスクで扱います。

予防は主に配置と、拒否の一層です。シークレットはドキュメントルートの外、リポジトリの公開出力の外に保持してください。危険な名前がそこに落ちてもサーバーが拒否するようにしてください——ドットファイル、env と設定の拡張子、アーカイブ、キー材料に対する拒否ルールを、実際にリクエストしてテストします——デプロイ成果物から .git を取り除くか、きっぱりブロックしてください。パイプラインでは、CI にシークレットスキャンを追加してください——コミット時には、キーが出荷前に止まるように、ビルド成果物には、バンドルされたキーが見知らぬ人ではなく出力の中で捕まるように。最後に、定期的に、そしてデプロイ変更のたびに自分でスキャンしてください。この記事の公開はすべて無音であり、他人より先に自分の公開を知る唯一の方法は、スキャナーが問うのと同じ質問を自分のサーバーに問うことです。

出典とさらに読むもの

よくある質問

公開された .env ファイルを削除しました。もう安全ですか?

まだです。削除で新しいダウンロードは止まりますが、コピーは発見者の手、CDN とプロキシのキャッシュ、クロールやアーカイブに存在するかもしれません。そのファイルに含まれていたすべての認証情報をローテーションし——古いキーを失効させ新しいものを発行し——キャッシュを消去し、そのパスのアクセスログを確認してください。コピーを無価値にできるのはローテーションだけです。

私のサイトは /.env に 200 を返します。ファイルは公開されていますか?

必ずしもそうではありません。多くのサイトは未知のパスすべてに 200 とトップページやアプリの外枠で応答します——キャッチオールのフォールバックです。重要なのは内容です。応答本文があなたのページなら何も公開されておらず、実在の値を持つキーと値の行なら公開されています。信頼できるスキャナーは内容で確認し、素の 200 は未確認として別に列挙します。

再発を防ぐために CI で何を実行すべきですか?

2つの時点での2つのチェックです。コミットに対するシークレットスキャナーはキーがリポジトリに入るのを防ぎ、ビルド成果物とデプロイされた出力ディレクトリのチェックは、ビルドがインライン化したものとデプロイがコピーしたものをつかまえます。最後の層としてドットファイルとキー材料に対するサーバーの拒否ルールを追加し、デプロイ変更後に外部プローブを再実行してください。