ガイドライン

サーバーサイドリクエストフォージェリ

サーバサイドリクエストフォージェリの脆弱性は、ユーザがアプリケーションに攻撃者が決めたドメインへの HTTP リクエストを行わせることができる場合に発生します。アプリケーションがプライベート/内部ネットワークにアクセスできる場合、攻撃者はアプリケーションに内部サーバへの リクエストを行わせることもできます。 

実際にどのようなものなのか、いくつかの例を挙げながら詳しく見ていこう。

ユーザーからURLを受け取り、ユーザーから提供されたURLの画像を生成するAPIを考えてみよう。 

ts
let url = request.params.url;

let response = http.get(url);
let render = response.render();

return render.export();

URLパラメータはユーザーによって制御されるため、攻撃者は単純に好きなURLにアクセスすることができる。URLへのアクセスに使用されるライブラリによっては、「file://」スキームを使用してローカルファイルにアクセスすることも可能です。  

SSRFの脆弱性を悪用する一般的な方法は、AWS上でホストされている場合、AWS API用の認証情報を含むAWS Metadata APIにアクセスするためにそれを使用することです。これは、アカウント内の他のAWSリソースへのさらなるアクセスにつながる可能性があり、想像できるように、理想的ではありません。

緩和

SSRFの脆弱性を緩和することは、時に非常にやっかいで、問題のコードが何を達成しようとしているかに大きく依存します。要件によって、導入できる緩和策は異なります。

ユーザーが決めたURLは避ける

場合によっては、ユーザーが任意のURLを提供することに依存しない方法で機能を実装できるかもしれません。もしこれが可能であれば、SSRFのリスクを軽減する最も効果的な方法です。

能力の最小化 

PDFエクスポート機能を実装する場合、単純にヘッドレス・ブラウザを使ってページのスクリーンショットを撮りたくなるかもしれない。ブラウザの複雑さや、ブラウザが公開する機能や攻撃対象の多さを考えると、これは必ずしも望ましいことではありません。

目の前の仕事に適したツールを使うことが重要だ。場合によっては、単純なHTTPクライアントで十分なこともある。機能を最小化するためにできることは常にあり、その結果、利用可能な攻撃面や攻撃ベクトルを最小化することができる。例えば、HTTPクライアントの場合:

  • 以下のリダイレクトを無効にする
  • HTTPS以外のすべてのスキームを無効にする

いくつかの落とし穴がある

リダイレクトと iframe

プライベートリソース(IPアドレスまたは内部ホスト名)上のSSRFから保護する一般的な方法は、ユーザーによって提供されたURLを解析し、機密性の高いリソースへのアクセスを防ぐために「deny-list」を使うことである。

クライアントがHTTPリダイレクトやHTML/JavaScriptリダイレクトに従ったり、iframeのような複雑なエレメントをレンダリングできるようなシナリオでは迂回できるので、この方法がほとんどの場合に有効でないことは注目に値する。

攻撃者は、HTTP 301/302、HTML Metaリダイレクト、ロード時のJavascriptによる現在のURLの設定、または内部リソースを表示するiframeの埋め込みによって、センシティブなリソースにリダイレクトするページをホストする脆弱なアプリケーションにURLを提供することができます。これにより、元のURLを検証する試みが効果的に回避されます。 

DNS Rebinding
別の「タイプ」のリダイレクトもDNSを通して行うことができる。SSRF攻撃を防ごうとする一般的な方法の一つは、次のようなものである:

  1. 指定されたURLを解析する
  2. ホスト名を取り出し、DNSルックアップを行う。
  3. URLが内部/プライベートIPに解決される場合は拒否し、パブリックIPである場合は受け入れる。

この方法は、「DNSリバインディング」に対して脆弱であるため、実際には有効ではない。DNSリバインドは、リモートホストによってTCPコネクションが閉じられたときの、ほとんどのネットワークスタック(LinuxやWindowsなど)の標準的な動作のために機能する。
リモートホストが接続を強制的に閉じると、IPアドレスを再解決するために別のDNSクエリを実行した後、再接続を試みます。 

これによって攻撃者は以下のことが可能になる:

  1. 非常に短いTTL(Time-to-live)でオープンなHTTPポートを持つパブリックIPアドレスで、`rebinding.attacker.com`のDNSエントリを作成する。
  2. 脆弱なアプリケーションに URL(例: https://rebinding.attacker.com/)を送信する。解決されたIPが非公開でないことを確認し、安全であると信じて要求された処理を続行する。
  3. HTTP接続が行われると、「rebound.attacker.com」のDNSエントリーが内部IPアドレスに変更される。
  4. HTTP接続が強制的に閉じられる
  5. これにより、アプリケーションは "rebound.attacker.com "のIPアドレスを再解決し、内部IPアドレスを指すようになりました。
  6. IP解決保護はすでに行われており、DNSエントリーの再解決と再接続はすべてカーネル内で行われるため、アプリケーションはIPが変更されたことに気づかない。

これは、プライベートIPアドレスに解決するURLの提供に対する保護を効果的に回避する。 

IPv4とIPv6の比較

あらゆる「拒否リスト」をバイパスするもう一つの一般的な方法は、IPv6の使用である。すべてのIPv4アドレスはIPv6アドレスで表すことができるため、アクセスしたいIPv4アドレスにマップされるIPv6アドレスを使うことで、拒否リストをバイパスできることがよくある。