ほぼ2年前、
StackExchangeサイト
ネットワークにかなり重大な脆弱性がありました。 私は「つまずいた」と言ったのは、サイトをハッキングしようとしなかったからです。 状況が私に扉を開いた。 脆弱性自体は非常に興味深いものであり、サイトまたはサーバーインフラストラクチャを作成および保守するすべての人に向けた教訓が含まれています。 だから、ここで私が
StackOverflowをどのようにハックしたかの物語です...
ソースデータ
当時私は小さな会社で働いていましたが、そこには完全に厳しい制限のあるファイアウォールがありました。 彼は、HTTP / 1.1仕様を満たさなかったすべての要求および応答ヘッダーをカットしました(さらに、有効なHTTP / 1.1ヘッダーもカットしました)。 これは、
X-Requested-With
ようなものに依存するサイトでトリックを演じました。 したがって、「外部の冒険」のために、プロキシを設定しました。
一度に複数のサーバーがあったので、そのうちの1つにSquidをインストールしました。 私は何かを考えていたので、
127.0.0.1
のみプロキシ接続を許可しました。 サーバーへのSSHトンネルを上げて、localhostをブラウザーのプロキシとして指定しました。 サーバー上のSquidに接続したトンネルに接続されたブラウザー。 すべてが完璧でした。 すべてのトラフィックが暗号化されたという事実に加えて、サイトを通常どおり使用する機会を得ました。
私が間違ったことをしたいあなたのために、私はこれをする機会があったという事実にあなたの注意を引きたいです。 また、単なる機会ではなく、プロキシを使用するように公然と言われました。ファイアウォールを介して機能しなかったいくつかのサイトで作業しなければならなかったからです。 だから私は「間違った」ことはしませんでした。
攻撃
当時、私はしばしばStackOverflowチャットに参加していました。 それから彼は現れたばかりで、それにいくつかのバグがありました。 ある晴れた日、サイトからコールスタックが表示され始めました。 私はこれをインターネット全体で頻繁に会ったので、これを重要視しませんでした。 実際、ASP.NETで記述されたサイトでエラーメッセージを受信するたびに、コールスタックが表示されました。
そして、チャットで新しいメニュー項目に気付きました。 この新しいメニュー項目は「管理者」と呼ばれていました。 好奇心から、私はアクセスを拒否されると信じて、リンクをクリックしました。 次に起こったことに驚いた。 すべてに完全にアクセスできました。 誰が何をしているのかを見ることができる開発者コンソールがありました。 データベースを操作するためのインターフェイスがあり、任意のデータベースから直接クエリを実行できました。 完全な管理者権限を取得しました。
次に起こったこと
次にやったことは、すぐにモデレーターに報告することでした。 数分後、私はモデレーターと2人の開発者とのプライベートチャットに参加しました。 理由は約10分以内に見つかりました。 さらに10分後、問題は表面的に解決されました。 完全な修正には数時間かかりました。 彼らは素晴らしかった。 私はまだそのチャットのログを持っています、そして、これらの開発者はすべての称賛に値すると言いたいです。 彼らは迅速かつ専門的に答えました。 そして、彼らはできるだけ早く問題を解決しました。
脆弱性
あなたが賢いなら、おそらく何が起こったのか推測したでしょう。 プロキシを介して終了したため、リクエストに
X-Forwarded-For
ヘッダーが追加されました。 このヘッダーの値は、プロキシが要求されたIPでした。 しかし、SSHトンネルを介してプロキシに接続したため、IPはローカルでした。 そこで、Squidは
X-Forwarded-For: 127.0.0.1
追加しました...
しかし、最も興味深いのは、ASPがログに表示したものです。 彼らが私のクエリのダンプを見ると、
REMOTE_ADDR: 127.0.0.1
レコードがありました
REMOTE_ADDR: 127.0.0.1
! アプリケーションでは、すべてのヘッダーチェックが正しく実装されました。 ただし、IISは正しく構成されておらず
REMOTE_ADDR
値
X-Forwarded-For
で上書きされます(存在する場合)。 また、このような構成エラーのおかげで、プロキシサーバーを使用して管理パネルにアクセスできました。
結論
見てのとおり、
X-Forwarded-For
に依存しないでください-安全ではありません。 常に
REMOTE_ADDR
使用し
REMOTE_ADDR
。 IPベースの保護が必要かどうかを検討する価値があります。 または、少なくとも、完全に依存するのではなく、追加の手段としてのみ使用する必要があります。
開発者が実際に適切なヘッダーチェックを使用したことに注意してください。 結論として、インフラストラクチャを盲目的に信頼することは絶対にしないでください。 この穴は、サーバーとアプリケーションの構成の違いが原因で発生しました。 このようなささいなことは毎日起こります。 アプリケーションは1つのことを想定し、サーバーは別のことを想定しています。 問題は、そのような信頼がセキュリティを完全に損なう可能性があることです。 この場合、開発者は
REMOTE_ADDR
(正当に正当化された)の値を信頼しましたが、サーバーは正しく構成されていませんでした。 もちろん、サーバーや他のコンポーネントを信頼する必要がある場合もありますが、ブラインドトラストは良いことではないことに注意してください。 それについて考え、そのような場合に備えて自分自身に保険をかけるようにしてください。
StackOverflowチームはこの問題を完全に解決しました。 高速で、応答性が高く、合理的です。 彼らは私に助けを求め(私は喜んで提供しました)、専門的かつ敬意を持って行動しました。 彼らは素晴らしい仕事をしました。 私たちは皆、レッスンを学ぶ必要があります。 脆弱性レポートに真剣に対応します。 問題を専門的かつ迅速に解決します。
PHPについて
ここで最も興味深いのは、PHPで作成されたアプリケーションにも同じ脆弱性が存在する可能性があることです。
Symfony2 Requestクラスを見てください。 よさそうだ。 プロキシを信頼すべきかどうかを判断するために静的変数を使用することに気付くまで。 これは、アプリケーションの一部がプロキシからヘッダーを取得する場合(たとえば、ログに書き込む場合)、アプリケーション全体がプロキシからヘッダーを受信することを意味します。 コードがこの脆弱性に対して脆弱かどうかを確認するには、その中のcall
$request->trustProxy()
ます。 また、リバースメカニズムはありません。 プロキシの「信頼を停止」することはできません。 これは大きな建築上の誤算だと思います...
Zend Framework 2も同様です。 (IPの取得に関して)同様の方法で動作する
クラスがあります。 興味深いことに、Zend Framework 1では、
IPアドレスを取得する方法は適切でした。 呼び出しコードは、受け取りたいものを明示的に示す必要があり、デフォルトでは安全なオプションが必要です。
おわりに
この問題は、2つの小さな誤算の組み合わせの結果でした。 それとは別に、それらは見落としやすいです。 しかし、それらが特定の方法で収束すると、非常に深刻なセキュリティリスクが発生します。 そして、最大の教訓は、あなたは本当にあなたのアプリケーション以外のものを信頼できないということです。 これを回避できる場合(たとえば、ヘッダーや
REMOTE_ADDR
などの変数を信頼しないことで)、アプリケーションをより安全にすることができます。 しかし、まず最初に、作成するコードと構築するシステムについて考えてください。 そしてそれらをサポートします。