リクエストフォージェリ(Request Forgery – リクエスト偽造)はかなり古くから知られている脆弱性です。恐らく1980年代から良く知られていたはずです。昔から知られているSSRFとCSRFの類似性を考えてみます。類似性を考えると、少し解りづらいCSRFも簡単に理解できるかも知れません。
そもそものリクエストフォージェリ – SSRF
SSRFとはサーバーサイドリクエストフォージェリの事です。
1980年代からSSRFがセキュリティ問題である、と指摘されていたと考えている理由はUNIXのリモートシェルの仕様と注意事項にあります。現在のUNIX系OSにはそもそもリモートシェル系のコマンド(rコマンドと呼ばれるrshなど)はインストールされていない物が多いと思います。そこでrコマンドとは何か、簡単に説明します。
rコマンドの代表であるrshは名前の通り、リモートからシェルコマンドを実行する仕組みです。rshなどのrコマンドはホームディレクトリの.rhostファイルに実行を許可するホストとユーザー名を定義してリモートコマンド実行を許可します。
参考:パスワード無しでrshする(英語)
ATTACKER1とSERVER1、SERVER2があり、SERVER1が攻撃対象だとします。
ATTACKER1 -> SERVER2 -> SERVER1
リモートシェルの仕組みを利用するとSERVER1が信頼するSERVER2にアクセスできれば、攻撃元となるATTACKER1から攻撃対象となるSERVER1に攻撃可能になります。
サーバーへの”信頼”を利用して、コマンドを送る、つまりリクエストを偽造して起きる問題として古くから知られていました。サーバーのリクエスト偽造するのでSSRF(Server Side Request Forgery)とも呼ばれています。
この種の攻撃は変形型が多数あります。CWEでもSSRFとしてカタログ化されています。同じくCWEでカタログ化されているXXEもSSRFの変形型です。他にも様々な派生系があります。
CSRF(クロスサイトリクエストフォージェリ)
CSRF(クロスサイトリクエストフォージェリ)も同様にCWEでカタログ化されています。簡単にCSRFを解説すると
- 罠(攻撃用)のWebページを用意し、攻撃用のURLを配置する
- 攻撃目標のWebサイトの正規ユーザーに罠ページにアクセスさせ、攻撃用URLをクリックさせる
- 攻撃目標のWebサイトに攻撃用URLが、正規ユーザーとして送られる
- 攻撃目標のWebサイトは正規ユーザーからのリクエストなので正しいリクエストとして処理する
典型的な攻撃用のURLは、コメントを送信するURLなどで
http://example.com/comment.php?id=1234&comment=EVIL_COMMENT
の様にリクエストを送信させます。Webアプリがユーザー認証を行っていても、リクエストが本当にユーザーが発行したものか検証しないと、正規ユーザーなので処理が行われてしまいます。
注意:リクエストフォージェリはGETリクエストだけ、とは限りません。POSTの場合にも対策が必要です。
SSRFとCSRF
少々乱暴ですがSSRFとCSRF単純に図解すると、
のような攻撃になります。
このような攻撃を防ぐには、送信者(サーバー/ブラウザ)が意図したモノであるか確認するためのトークンが利用できます。
Web環境の場合、どのWebサーバーでも攻撃用のURLを配置できるのでこのような方法は取れません。このためCSRF対策としてトークンを渡し、リクエストの正当性を検証します。このトークン方式はSSRFでも一応有効です。実際にはリモートシェルによる攻撃を防御するには認証を強化(SSHなどを使う)して対応します。
コマンド/リクエストを発行した主体(ユーザーやプログラム)が本当にそのコマンド/リクエストを発行していると証明するトークン(鍵)を利用する、という考え方は真正性(Authenticity)を保証するにはとても有効な考え方です。開発者はこういった対策が有効であることを知っておく必要があります。
SSRFとCSRFの類似性
SSRFとCSRFは類似するセキュリティ問題であることが解ると思います。個人的にはCSRFはCross Site Request ForgeryとするよりClient Side Request Forgeryの略とした方が解りやすいのではないか?と考えています。
- SSRF サーバーが持つ権限・認証を利用して不正な命令を実行
- CSRF クライアントが持つ権限・認証を利用して不正な命令を実行
まとめ
システム/ユーザーが持っている権限を利用して不正に機能を使う攻撃です。認証/認可を正しく管理していても、システム構成やプロトコルなどによって権限を悪用できる脆弱性ががリクエストフォージェリです。
私はCSRFという言葉が生まれる前から、更新系リクエストには二重送信防止も含めて使い捨てのでID(トークン)を利用する方式を使ってしました。現在ではサーバー側で自動で期限切れになるmemcachedを使えば、使い捨てIDの管理はとても簡単にできます。
CSRF防止用のトークンに固定ID(トークン)を利用する方式はよりリスクがあります。実際、CRIME/BREACH(SSL通信の内容を解析する攻撃)ではCSRF用トークンの解析に利用できたことが知られています。
クロスサイトリクエストフォージェリと言うとなんだか難しく感じるCSRFですが、リクエストフォージェリの一種でクライアントサイドリクエストフォージェリだ、と理解すると多少は解りやすいのではないでしょうか?また複数存在するSSRF(またはクライアント側で発生するリクエストフォージェリ)がどのような脆弱性なのか?どのような場合にリスクが発生するのか?も簡単に理解できるのはないでしょうか。
Webアプリにおいて、リクエストフォージェリを防止するためには2つの対策が重要です。
- リクエストの真正性を証明するID/トークンを付与する(CSRF対策)
- リクエストのパラメータが予定しているパラメータかバリデーションする(数、タイプ – 余計な物は受け付けない)(SSRF対策)
余計なパラメータを受け付けないことが、なぜ重要なのかはXXE問題を理解すると良く解ると思います。
正しくリクエストフォージェリを理解する、ということはセキュリティの基本要素である真正性(Authenticity)を正しく理解する、ということです。詳しくはブログで書きます。真正性とは何か?を理解している方にはここに書いたことだけで十分意図が通じると思いますが、真正性の概念を教えられていない方には難しいと思います。因みにISO 27000では真正性はセキュリティの基本要素で、どう注意すべきなのか、も記述されています。
参考: