オープンソースの脆弱性対策に学ぶ ~DrupalのSQLインジェクション対策(SA-CORE-2015-003、CVE-2015-6659)~ 3/4
前回はSQLインジェクションの脆弱性と、その対策方法としてエスケープ、値のチェック、プレースホルダー、ビルダーライブラリがあることをご紹介しました。
SQLインジェクションの脆弱性の対策方法を、値を埋め込む位置で整理しますと下表のようになります。
SQL文に値を埋め込む位置 | 対策方法 | |||
---|---|---|---|---|
エスケープ | 値のチェック | プレースホルダー | ビルダーライブラリ | |
リテラル | ||||
文字列リテラル | ○ | △ (常にできる とは限らない) |
○ | ○ |
文字列以外のリテラル (数値など) |
– | ○ | ○ | ○ |
その他 | ||||
オブジェクト識別子 (テーブル名、カラム名、 ビュー名、プロシージャ名など) |
– | ○ | – | ○ |
予約キーワード (SELECT、FROM、AND、OR、= など) |
– | ○ | – | ○ |
コメント | – | ○ | – | ○ |
一見するとビルダーライブラリが万能のように思えますが、ライブラリの内部では他の対策を実装しています。
したがって、その実装に不備のない確かなライブラリを選定することが対策の大前提になります。
これに加えて、セキュアコーディングの立場から言えば、ライブラリを使用する以外の方法でデータベースにアクセスすることを禁止する必要があります。
ただ単にルールとして禁止するだけでなく、そのようなコードの記述を不可能にできれば理想的です。
しかし、現実はコードレビューでルールに違反した記述を検出するというのが実情かと思われます。
また、プレースホルダーは効果の高い対策方法ですが、リテラル以外の位置には使用できません。
本質的には、エスケープと値のチェックが対策の基本となります。
考察
話をDrupalに戻しましょう。
Drupal ver.7.39で対策されたSQLインジェクションの脆弱性は、SQLコメントの位置に値を埋め込んでいると考えられます。
SQLコメントはその名の通りコメントであり、一部の例外(※)を除けばSQLの動作に何ら影響しません。
(※ 例えばOracleデータベースの場合、オプティマイザに与えるヒントをSQLコメントに記述することで、パフォーマンスチューニングを行うことができます。)
そうであるなら、アプリケーションが動的にSQLコメントの位置に値を埋め込む理由は、通常は思い当たりません。
では、なぜDrupalはSQLコメントの位置に値を埋め込む処理を実装しているのでしょうか。
気になってソースコードを追いかけてみましたところ、この処理はビルダーライブラリとして実装されたものであることが分かりました。
Drupalには実行したSQL文をログに記録する仕組みが備わっており、ログ中のSQLコメントを確認することで、アドオンモジュール開発者が容易にデバッグを行えることを意図しているようです。
なお、Drupal自身(Drupal Core)はこの処理を呼び出していないので、恐らくはアドオンモジュールがこの処理を呼び出す際に脆弱性の問題が顕在化するものと考えられます。
調査の結果、少なくともViewsモジュールにおいて顕在化する可能性のある箇所を確認できました。
さて、変更前のソースコードには、SQLコメントの位置に埋め込む値の中から「/* 」や「 */」といった部分文字列を見つけて除去する処理が記述されていました。
この処理にどういった値が渡された場合に、SQLインジェクションの脆弱性の問題が顕在化するでしょうか。
例えば、ブロックコメント「/* ~ */」中にブロックコメント終端「*/」が登場する場合には問題が起きるのですが、変更前のソースコードは「*/」を除去していますので、一見すると対策されているように思われます。
しかし、よくよく考えるとここに論理の抜けが存在しているのです。
タネ明かしは、次回のお楽しみです。