2016年3月7日月曜日

OWASPのSQLインジェクション対策方針を読んで「おまえは俺か」と思った

つい最近まで、グローバル・スタンダードのセキュリティ施策ではバリデーションが極めて重視されている、いささか過剰ではないかと思っていたのですが、OWASPの文書を読みなおしたところ、これは僕の思い過ごしだったかと思い始めました。あくまでOWASPに限った話ではありますが…
OWASP Top 10 2004については、以下のようなプレゼンをしたことがあります(2012年3月27日)。
OWASP Top 10 2004をはじめとして、バリデーションが過剰に重視されているのではないかという指摘でした。
しかし、最近OWASPの文書を読みなおしてみると、OWASP Top 10 2004当時にあった「バリデーション至上主義」のようなものはすっかり影を潜め、私が(そして日本の専門家の多くが)言っていることとほとんど変わらないことに気が付きました。以下、SQLインジェクション対策に焦点を絞り、以下の3種類の文書を元に説明します。
  • OWASP Top 10
  • SQL Injection Prevention Cheat Sheet
  • OWASP Top 10 Proactive Controls

OWASP Top 10

OWASPのドキュメントでももっとも有名なものがOWASP Top 10ですが、副題としてThe Ten Most Critical Web Application Security Risksとなっているように、ウェブアプリケーションにおいても重大なセキュリティリスクのトップ10を集めたものです。その最初の版である2004年版では、筆頭に「Unvalidated Input(検証されていない入力)」がありました。その後2007、2010、2013と改版されており、2007以降ではUnvalidated Inputはトップテンからは消えています。2010以降の第1位は、Injection(SQLインジェクション、OSコマンドインジェクション等)となっています。

そこまでは認識していたのですが、2013年版のInjectionの解説では防御方法が以下のように説明されています。実は2010年版もほぼ同じです。
防止方法
インジェクション攻撃を防止するには、コマンドとクエリから信頼出来ないデータを常に区別することが必要です。

1. 推奨されるオプションは、インタープリタを全く用いない安全なAPIを利用するか、パラメータ化されたインターフェースを用いる事です。ただ、ストアードプロシージャなどの、パラメータ化していてもインジェクション攻撃が可能なAPIには注意して下さい。

2. パラメータ化されたAPIが利用出来ない場合、インタプリタにて定められたエスケープ構文を用いて特殊文字のエスケープ処理を慎重に実施すべきです。OWASP's ESAPIはこれらの定番のエスケープを多く提供します。

3. 多くのアプリケーションが特殊文字の入力を必要とするため、“ホワイトリスト”による入力検証も推奨しますが、完全な防御ではありません。特殊文字が必要な場合、上述の1.と2.を用いることで、安全に使用出来ます。OWASP's ESAPIは、ホワイトリストの入力検証ルーチンの拡張可能なライブラリがあります。

https://www.owasp.org/images/7/79/OWASP_Top_10_2013_JPN.pdfより引用
1はプレースホルダを使えということですね。「インタプリタを全く用いない」とは、静的プレースホルダを指すのでしょう。動的プレースホルダ(俗にいうクライアントサイド・プリペアードステートメント)は、呼び出し側でSQLを構文解析するので、インタプリタを用いることになります。
また、「ホワイトリスト」の定義が曖昧ですが、「特殊文字が必要な場合」とはアプリケーション仕様として特殊文字を許容する場合という意味でしょうから、ホワイストリストも「アプリケーションの仕様に従って」という意味だと考えます。
つまり、以下の様になりますね。
  • 根本的対策としてはプレースホルダの使用か記号文字のエスケープである
  • 可能な限りプレースホルダの使用を優先すること
  • アプリケーションの仕様にしたがって入力値検証することを推奨するが、完全な防御にはならない
これなら概要としてはまったく同意ですので、目くじらを立てる必要もないのでした。

SQL Injection Prevention Cheat Sheet

SQLインジェクション防御のチートシート(カンニングペーパー)というタイトルのドキュメントです(英語版)。こちらについては、OWASP名義で下記の記事を投稿しましたのでご笑覧ください。
肝心の防御方法については以下のように書かれています。
  • Defense Option 1: Prepared Statements (with Parameterized Queries)
  • Defense Option 2: Stored Procedures
  • Defense Option 3: Escaping All User Supplied Input
ストアド・プロシージャについては前述の私の記事でマイルドにツッコミを入れていますので参考にしてください。また、前述のOWASP Top 10でもストアド・プロシージャに対するツッコミが入っていますね。このツッコミに私は同意します。

また、本稿と関連するトピックスについては下記のように書かれています。
まずエスケープに関して。

Defense Option 3: Escaping All User Supplied Input

This second technique is to escape user input before putting it in a query. However, this methodology is frail compared to using parameterized queries and we cannot guarantee it will prevent all SQL Injection in all situations. This technique should only be used, with caution, to retrofit legacy code in a cost effective way. Applications built from scratch, or applications requiring low risk tolerance should be built or re-written using parameterized queries.

【参考訳】この第2の手法は、ユーザ入力をクエリ内に入れる前にエスケープすることです。しかし、この方法論はパラメータ化クエリ(訳注:プレースホルダを用いたSQL呼び出しのこと)を用いる場合と比較して弱く、我々はそれがすべての状況ですべてのSQLインジェクションを防げると保証することができません。この手法は、既存のコードを費用対効果がよい方法で改修する場合に限り、用心深く用いられるべきです。スクラッチから構築するアプリケーションや、リスク許容度の低いアプリケーションは、パラメータ化クエリを用いて構築あるいは書き換えされるべきです。
バリデーションについて。

3 Additional Defenses

3.2 White List Input Validation
Input validation can be used to detect unauthorized input before it is passed to the SQL query. For more information please see the Input Validation Cheat Sheet. Proceed with caution here. Validated data is not necessarily safe to insert into SQL queries via string building.

【参考訳】無許可の入力がSQLクエリに渡される前に検知するために入力バリデーションを用いることができます。詳細は、入力値検証チートシートを参照ください。以下に注意して下さい。バリデーションされたデータは、文字列組み立てを通じてSQLクエリに挿入する上では必ずしも安全ではありません
方向性としては前項のOWASP Top 10と同じですが、エスケープについては、より強く使わないことを推奨しています。引用した内容について、私は完全に同意します。

OWASP Top 10 Proactive Controls

こちらは、「Proactive Controls」ですから、事前の対策についてまとめられたものですね(英語版日本語版)。先ほどのSQL Injection Prevention Cheat Sheetよりも全体的な話題となります。トップテンは下記の通りです。
  1. 早期に、繰り返しセキュリティを検証する
  2. クエリーのパラメータ化
  3. データのエンコーディング
  4. すべての入力値を検証する
  5. アイデンティティと認証管理の実装
  6. 適切なアクセス制御の実装
  7. データの保護
  8. ロギングと侵入検知の実装
  9. セキュリティフレームワークやライブラリの活用
  10. エラー処理と例外処理
1の「セキュリティを検証」とは、脆弱性の検査を開発プロセスの中で繰り返し行えということですね。
問題は2から4です。SQLインジェクションについては、2のクエリーのパラメータ化、すなわちプレースホルダを使えと書かれています。
SQLインジェクションを防ぐには、信頼できない入力値がSQLコマンドの一部として解釈されるのを避ける必要があります。最も良い方法は「クエリーのパラメータ化」と呼ばれる実装方法です。この方法では、SQLの問い合わせ構文とパラメータは、それぞれ別々にデータベースサーバーに送信され、データベース上で解析されます
「SQLの問い合わせ構文とパラメータは、それぞれ別々にデータベースサーバーに送信され」の部分はわかりにくいですが、これは静的プレースホルダの性質を説明しています。詳しくは「安全なSQLの呼び出し方」の解説を参照下さい。つまり、OWASP Top 10とは別の表現で、動的プレースホルダではなく静的プレースホルダを使えと推奨しているのです。

3の「テータのエンコーディング」とはエスケープ処理のことですが、この節では主にXSSを例示に用いています。SQLインジェクションも同じ方法で対策することは可能ですが、本文中ではエスケープによるSQLインジェクション対策については触れられていません。

4の「すべての入力値を検証する」については面白いことが書いてありました。

入力チェックとセキュリティに関する補足

入力チェックの段階では、信頼できない入力値を「無害な状態に」変換してしまう必要はありません。危険と思われるデータも「正しいデータ」として受け入れなければならない場合があります。潜在的に危険な文字も「正しいデータ」として受け入れなければならない場合があるため、入力検証によって信頼できない入力が無害になるとは限りません。アプリケーションのセキュリティは、入力値が実際に使われる箇所で担保されるべきです。たとえば、入力値をHTMLの一部として出力するのであれば、クロスサイトスクリプティング対策としてHTMLエンコーディングを実装します。同様に、入力値をSQL文の一部として使うのであれば、クエリーのパラメータ化を使います。どのような場合であれ、セキュリティ対策を入力チェックに依存してはいけません
『「無害な状態に」変換してしまう必要は』ないというのは、サニタイズは無用だということでしょうね

(2016/3/7 14:00追記)
奥さん(@kazuho)から指摘をいただきました。Input validation does not necessarily make untrusted input “safe” since it may be necessary to accept potentially dangerous characters as valid input. の訳として、『信頼できない入力値を「無害な状態に」変換』は誤訳であり、「入力値検証によって、信頼できない入力値が無害なものになるとは限りません」くらいの意味であるということです。確かにそうですね。引用した訳はOWASPジャパン有志による翻訳ですが、ここは重要な箇所なので私訳に差し替えました。
(追記終わり)


そして、「アプリケーションのセキュリティは、入力値が実際に使われる箇所で担保されるべきです」という文句がいいですねぇ。「おまえは俺か」と思いましたよ。例えば、次の記事で書いたようなことですね。
この記事で私は以下のように書きました。
これは、入口でのチェックだと漏れやすいから、脆弱性が発生するその箇所で対策するという考え方にシフトしているのだと私は考えます。
ここで念押ししておかなければなりませんが、「入力チェックをしなくていい」、なんて誰も言ってないですからね。入力チェックはするべきですが、SQLインジェクション対策という文脈では、入力チェックをあてにしてはいけない、ということです。バリデーションしていれば防げたのに、という脆弱性はたくさんあります。その辺については以下の資料にまとめています。

まとめ

OWASPの最近の主要ドキュメントを読む限り、SQLインジェクション対策の方法論について日米(日本とグローバル)の差はほとんどないことが分かりました。まとめると以下のようになります。
  • とにかくプレースホルダを使う
  • どーーしてもプレースホルダを使えないとか、既存アプリの脆弱性対処を素早く行う必要がある場合に限りエスケープ手法を用いる
  • バリデーションはすべきだが完全ではないので保険的に用いること
私のブログの読者にとっては目新しいことは何もないと思いますが、私は私なりに、グローバル・スタンダードとしての脆弱性対策と日本のそれに差異があることを気にしていたのです。「日本独自の脆弱性対策手法」なんていうと、何かガラパゴス的なものを連想するではありませんか。しかし、こうして米国側から「歩み寄って」下さったおかげで、もはやガラパゴスなんて心配は無用であり、私はいい気持ちになりました。


【HASHコンサルティング広告】
HASHコンサルティング株式会社は、SQLインジェクションの正しい対策方法に関心のあるセキュリティエンジニアを募集しています。
興味のある方は、twitterfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。


1 件のコメント:

  1. OWASP Top 10 Proactive Controlsの翻訳に携わった渡邉です。誤訳のご指摘の件、ありがとうございます。
    先週、翻訳チーム側に情報を共有いたしましたので、適切なタイミングで修正させていただきます。

    返信削除

フォロワー

ブログ アーカイブ