今年の2月にSAMLライブラリの脆弱性が報告されていたことを覚えている人も居ると思います。
この脆弱性はXMLコメント(<!– –>)の取り扱いの違いによって、本来のユーザーではない攻撃者を認証してしまう事が問題であったとしています。
攻撃用の文字列サンプルは以下のような物です。
<NameID>user@example.com<!—->.evil.com</NameID>
攻撃が可能になる理由はXMLコメントの取り扱いの違いにあります。
- あるライブラリは<!– –>までの文字列(user@example.com)までをNameIDとして取り扱う
- 別のライブラリは<!– –>を取り除いた文字列(user@example.com.evil.com)をNameIDとして取り扱う
これにより攻撃者が別のユーザーに成り済ませてしまう問題が発生しました。1
出力時のフェイルセーフ対策
SAMLライブラリの脆弱性の報告ページにはRemidiations(脆弱性対策)として色々な回避策が書かれています。ここではこれらは紹介しません。
残念ながら紹介されている脆弱性対策には大きな見落しがあります。攻撃パターンの
<NameID>user@example.com<!—->.evil.com</NameID>
には通常データとしてはあり得ない文字列が含まれていることに気付いた方も少なくないと思います。
user@example.com<!—->.evil.com
は”XMLのデータ”として出力されるデータです。XML要素を含まない“XMLのデータ”(タグの中の文字列)は出力前にXMLエスケープされなければなりません。
“<“を”<”などとXMLエスケープさえしていれば、XML処理ライブラリのコメントを含む場合の動作仕様の違いに影響を受けません。
user@example.com<!—->.evil.com
これならどのXML処理ライブラリでも文字列全体を1つの文字列(XML要素内のテキスト)として扱います。
本来やっておくべきセキュリティ対策
エスケープして
user@example.com<!—->.evil.com
となり成り済まし攻撃を防げたとしても、Eメールアドレスであるはずの部分に出鱈目な文字列を設定されたデータが送信されてしまうのはバグです。
本来やっておくべきセキュリティ対策は入力バリデーションです。コンピューターが正しい/妥当なデータでしか正しく動作しない、これはプログラムの動作原理です。このケースの場合、Eメールアドレスであることをバリデーションするのが当たり前です。
参考:どこでバリデーションしてもOK、ではないです。バリデーションはFail Fast原則に従って行います。
コメントで文字列分割が起きなくても問題が起きる場合もある
EメールアドレスにXML要素をインジェクションされたとして何も問題ないでしょうか?
答えはNOです。
HTML要素にインジェクション攻撃を行う場合と同じく、XML要素に好き勝手にインジェクション攻撃が可能です。XML文書によっては不正なデータ操作も可能になります。
本来やっておくべき入力データバリデーションとフェイルセーフ対策としてのエスケープを実施していないと、インジェクション攻撃に脆弱なコードになります。
APIを使っていれば大丈夫!と過信して必要な対策コードがないと大丈夫でなくなります。APIを使っていれば大丈夫、バリデーションもエスケープも必要ない!とする雑なセキュリティ対策では問題を作ってしまいます。
このような間違いを防ぐ思考方法 – エスケープファーストで考える
なぜこのようなおかしな事になってしまったのか?
このアドバイザリの対策方法も”的を射ている”とは言い難い内容でした。脆弱になってしまった理由は”XMLコメントの取り扱いの違い”ですが、本質的な脆弱性対策ではありません。
- 正しい/妥当なデータを送る
- その為に「エスケープファーストで考える」
これが本質的な脆弱性対策です。
「エスケープファーストで考える」は、何でもエスケープする、ではありません。”意味を持つ文字”がデータに一文字でもある場合、セキュリティ対策が必要になります。セキュリティ対策を漏れ無く実施するために「エスケープを一番に考える」が必要になります。
- 意味を持つ文字に対するエスケープ方法/エスケープAPIはあるか?(注意:エスケープ方法は定義されているのに、エスケープAPIがない仕様も多い)
- エスケープして無害化したデータは”妥当”なのか?(正しいのか?)
- 妥当にならない場合、どのようにバリデーションすべきか?(これにはエスケープの知識と正しいデータ形式の知識が必要。参考:3種類のバリデーション)
- 意味を持つ文字を無害化する他のAPIはあるのか?(例:SQLならプリペアードクエリ)
上記のような順番で考えると、つまりエスケープを第一に考えると、ライブラリ等の特殊文字(=意味を持つ文字)の取り扱いの違いにより攻撃可能な脆弱性を作ることがありません。エスケープを知るのはテキストインターフェース処理で最初に知るべき基本中の基本です。
よく見落されがちなのは多重化された出力コンテクストです。出力先のコンテクストは1つに限りません。全てのコンテクストに対してエスケープ方法が定義されているのか?理解した上で対策をしないと問題を作る原因になります。
「APIに任せておけばよい」といった危険な考え方ではセキュリティの維持は危ういです。
まとめ
念のために書いておきます。もしXMLコメントがあるとSAML認証成り済ましが可能なコードの場合、ライブラリを更新するだけだと不十分です。入力データのバリデーション、出力データのエスケープ、これら両方を行うコードが必要です。2
バリデーションは要らない、エスケープも要らない、と勘違いしている開発者が書いたコードの場合は成り済まし攻撃(とXMLインジェクション攻撃)に脆弱なコードを書いてしまっていると思います。
処理系(ライブラリなど)によって不正なデータの解釈が異なり、それにより攻撃が可能になるケースは少くありません。
- ヌル文字インジェクション
- 改行インジェクション
- 壊れた文字データのインジェクション
- 制御文字のインジェクション
これらの攻撃は不正なデータを検出&廃除することにより防げる脆弱性がほとんどです。
不正なデータを検出&廃除する、はブラックリスト型対策でダメな対策です。
不正なデータを検出&廃除ではなく、正しい/妥当なデータだけを受け入れるホワイトリスト型の対策でなければなりません。
参考: この脆弱性の本質は7PK(CWE-700として定義されている業界標準のソフトウェアセキュリティ分類)の「APIの乱用」です。SAMLのAPI仕様/制限を無視し、適切な利用方法で使わなかったことが問題の原因です。
-
- 他の動作としては<!– –>を含めたデータを返すがあります。 ↩
- 両方行っていれば、ライブラリを更新しなくても脆弱にはなりません。 ↩