Node.jsアプリケーションでサーバーサイドリクエストフォージェリを防ぐ
David Ekete
2024年2月20日
0 分で読めます
サーバーサイドリクエストフォージェリ(SSRF)は、Node.jsアプリケーションで知らないうちに発生することがある、一般的な脆弱性です。攻撃者がサーバーを操作して、内部および外部のリソースに意図しないリクエストを送信させる可能性があるため、重大な脅威となります。
この記事では、SSRFとは何か、その潜在的なリスク、Node.jsアプリケーションでSSRFを軽減する方法について解説します。
ぜひご覧ください: Snyk Learnのインタラクティブなサーバーサイドリクエストフォージェリのレッスンに取り組んでみましょう。
SSRFとは?
SSRFは、攻撃者が入力の改ざんやURLの操作によって、Webアプリケーションのサーバーから送信されるリクエストを悪用すると発生します。
入力の改ざんとは、アプリケーションの脆弱性を悪用するために、多くの場合ユーザーが作成したデータを不正に変更することです。一方、URL混乱の脆弱性では、URLを変更してシステムをだまし、許可されていないリソースへのアクセスや不正なリクエストなど、意図しない動作を実行させます。
攻撃者に操作されたサーバーは、あたかもサーバー自身が開始したかのように改ざんされたURLにリクエストを送信し、一般的なセキュリティ対策を回避します。SSRF攻撃に成功すると、攻撃者は内部リソース、データベース、ファイルにアクセスし、認証情報などの機密データを漏えいさせる可能性があります。
たとえば、特に注目されたSSRFインシデントの1つでは、Amazonの元ソフトウェア開発エンジニアがSSRFの脆弱性を悪用し、社会保障番号14万件、銀行口座番号8万件、社会保険番号100万件が流出しました。この侵害は1億600万人に影響を与え、損害額は2億5,000万米ドルに上りました。
SSRF攻撃の簡単な例
SSRFの脆弱性をより深く理解するため、具体例を見てみましょう。この例では、ユーザーがURLを入力すると、そのURLから画像を取得してユーザーに表示するWebアプリケーションを開発しているとします。
一緒に試す場合は、Webアプリケーションのソースコードを含むこちらのGitHubリポジトリをクローンしてください。このアプリケーションは、Webサービスの構築を簡単にするNode.jsフレームワークのExpressと、Node.jsからリクエストを送信できるHTTPライブラリのAxiosを使用しています。
Gitを使ってリポジトリをクローンするには、次のコマンドを実行します。
注意:このコマンドを実行するには、システムにGitがインストールされている必要があります。
GitHubリポジトリをクローンしたら、次のコマンドを実行して依存関係をインストールします。
注意:このコマンドを実行するには、Node.jsとnpmがインストールされている必要があります。
このアプリケーションには、次の3つのルートがあります。
/upload-image-urlでは、URLを使って画像をアップロードできます。誰でもアクセスでき、一見すると問題がないように見えます。/usersは、アプリケーションのすべてのユーザー情報を返します。一般公開すべきではありません。/users/:id/profileは、特定のユーザーのプロフィールを返します。一般公開すべきではありません。
次のコマンドでアプリケーションを起動します。
Insomnia(またはその他のAPIテストツール)を使って、有効な画像URLを指定して/upload-image-urlにリクエストを送ると、次のレスポンスが返されます。

悪意のあるユーザーはこのレスポンスから、指定されたURLを使ってサーバーが内部的にAPI呼び出しを行うことを把握できます。すると、さまざまなURLを試してサーバーの内部構造を調べたり、アプリケーションがAmazon Elastic Compute Cloud(Amazon EC2)インスタンス上で動作している場合に、http://169.254.169.254やhttp://instance-dataなどのURLを渡して、アプリケーションのAmazon Web Services(AWS)メタデータにアクセスしたりできます。このタイプのSSRFは基本型SSRFと呼ばれます。
基本型SSRFは、攻撃者がサーバーの内部構造を直接把握していないことも多い中で、意図しないリソースにリクエストを送信するようサーバーを操作すると発生します。この場合、通常、攻撃者はリクエストのレスポンスを確認できます。
もう1つのタイプはブラインドSSRFです。攻撃者はSSRFリクエストを送信しますが、サーバーのレスポンスに直接アクセスできません。その代わりに、アプリケーションの挙動から間接的にSSRF攻撃の成否を確認します。
たとえば、攻撃者がlocalhost:8050/usersというURLを試すと、次のレスポンスが返され(つまり基本的なSSRFの例です)、ユーザーデータがすべて漏えいします。

このコードは、適切な検証やアクセス制御を行わずにユーザーが指定したURLを受け入れるため、SSRF攻撃に対して脆弱です。ユーザーは、機密性の高い可能性がある内部リソースやプライベートリソースにリクエストを送信できます。また、特定のドメインを許可リストや拒否リストで管理する仕組みもありません。
この脆弱性を軽減するには、ユーザー入力をサニタイズし、信頼できるドメインへのアクセスを制限するとともに、ファイアウォールを使用し、適切なエラー処理と監視を実施する必要があります。
Node.jsでSSRFの脆弱性を防ぐ方法
Node.jsアプリケーションのSSRF脆弱性を防ぐには、いくつかの方法があります。次のセクションでは、役立つ手法とベストプラクティスをご紹介します。
ライブラリを最新バージョンにする
ライブラリを最新バージョンに保つことは、アプリケーションのセキュリティを強化するうえで重要です。新しいバージョンには、重要なセキュリティパッチやバグ修正が含まれることが多く、SSRFのような一般的な攻撃に対するアプリケーションの脆弱性を軽減できます。
ただし、更新時には互換性の問題、破壊的変更、後方互換性を考慮することが重要です。非推奨化のスケジュールに注意し、大規模なコードベースは段階的に更新しましょう。また、アプリケーションの安全性と保守性を維持するため、依存関係に潜在的なセキュリティ脆弱性がないか定期的に分析してください。
Snykを使ってライブラリをアップグレードし、依存関係を最新の状態に保ち、一般に知られているセキュリティ脆弱性を解消しましょう。
ファイアウォールを使う
ファイアウォールは、あらかじめ定めたルールに基づいてネットワークトラフィックを監視・制御する、防御壁として機能するネットワークセキュリティシステムです。
ファイアウォールでSSRF攻撃を防ぐには、Webアプリケーションファイアウォール(WAF)を導入します。信頼できるドメインの許可リストを作成し、不審なURLやIPアドレスを拒否することで、悪意のあるリクエストを検査してブロックできます。
ユーザー入力をサニタイズする
入力のサニタイズとは、アプリケーション内で安全に処理できるよう、ユーザーが提供したデータを無害化・変更するセキュリティ対策です。主な目的は、信頼できない入力や悪意のある入力に起因するセキュリティ脆弱性を防ぐことです。
すべてのユーザー入力をサニタイズし、URLが適切な形式で予期しない文字を含んでいないことを確認してからアプリケーションで処理すれば、SSRFを防ぐことができます。
入力のサニタイズはURLが正しい形式かどうかを確認するのに役立ちますが、これだけに頼るべきではありません。
URLスキームを制限する
SSRFの脆弱性を防ぐもう1つの方法は、特定のURLスキームのみを許可することです。アプリケーションで使用できるURLスキーム(たとえばHTTPやHTTPS)を指定すれば、危険または不要なスキーム(たとえばfile://やftp://)を含むURLの入力を制限できます。
先ほどクローンしたアプリケーションにこれを実装するには、指定されたURLが許可するスキーム(通常はhttp://またはhttps://)で始まることを明示的に確認します。URLがこれらのスキームに準拠していない場合は、拒否できます。
信頼できるドメインの許可リストを作成する
信頼できるドメインの許可リストを作成すると、アプリケーションに必要な安全性が確認された特定のドメインへのリクエストのみを許可できるため、SSRFの脆弱性を防げます。
先ほどクローンしたアプリケーションに実装するには、信頼してアプリケーションからのリクエストを許可するドメインを含む配列を作成します(実際のアプリケーションでは、より堅牢な方法が必要になる場合があります)。これらのドメインは、アプリケーションがやり取りする、安全だと判断したドメインである必要があります。
次に、ユーザー指定のURLにリクエストを送る前に、許可リスト内の信頼できるドメインと一致するか確認します。一致しない場合はリクエストをブロックします。この実装後、/upload-image-urlルートは次のようになります。
このコードでは、許可するドメインの配列を追加し、ユーザーが渡したURLが許可リストに含まれるか確認します。URLが許可リストにない場合は、リクエストを拒否するよう/upload-image-urlルートを変更しています。
Snyk IDE拡張機能で脆弱性を検出する
Snykは、オープンソースライブラリに含まれるSSRFなどの脆弱性の特定と修正に役立つ、広く利用されているセキュリティツールです。Snykは、Visual Studio Code(VS Code)をはじめ、さまざまな開発環境やIDEと連携できます。
VS CodeにSnyk IDE拡張機能をインストールするには、左サイドバーの四角いアイコンをクリックするか、Ctrl + Shift + X(macOSではCmd + Shift + X)を押して、拡張機能ビューを開きます。

拡張機能マーケットプレースで「Snyk」を検索し、Snyk拡張機能の横にあるインストールボタンをクリックします。

拡張機能をインストールしたら、Snykアカウントで認証する必要があります。Snykアカウントをお持ちでない場合は、今すぐ登録してください。Snykアイコンをクリックし、Snykの認証情報を使ってサインインします。
次に、VS Codeでクローンしたプロジェクトリポジトリを開きます。Snykがこれらのフォルダーを信頼してよいか確認するメッセージが表示されたら、フォルダーを信頼して続行をクリックします。

コード内の脆弱性がある箇所(つまり19行目のaxios.get)に赤い波線が表示されます。波線にカーソルを合わせると、脆弱性について説明するモーダルが表示されます。

または、Snykアイコンをクリックしてコードセキュリティを選択すると、セキュリティ上の問題を確認できます。特定の脆弱性を選択すると、Snykが左サイドバーを開き、問題の解決に役立つコード例を表示します。

まとめ
この記事では、Node.jsアプリケーションをSSRFから保護することの重要性と、そのために役立つ対策やベストプラクティスをご紹介しました。
ライブラリを最新バージョンに保ち、URLスキームを制限し、許可リストを導入し、Snykなどのセキュリティツールを利用することで、アプリケーションにおけるSSRF脆弱性のリスクを大幅に減らせます。さらに、開発ワークフローにSnykを組み込めば、本番環境にリリースする前にコード内のSSRFやその他の脆弱性を効率的に検出できます。コードを強化し、潜在的な攻撃からシステムを守りましょう。
今すぐ始めましょう!Snykでアプリケーションの保護を開始!
Capture the Flagを始めよう
オンデマンドのバーチャル入門ワークショップで、Capture the Flagの課題の解き方を学びましょう。


