2016年12月19日月曜日

PDOに複文実行を禁止するオプションが追加されていた

エグゼクティブサマリ

PHP 5.5.21、PHP 5.6.5 以降、PHPにPDO::MYSQL_ATTR_MULTI_STATEMENTSというオプションが追加され、PDO+MySQLの組み合わせで、SQLの複文を禁止できるようになった。この設定はSQLインジェクションの緩和策として有効である。

はじめに

2013年12月に公開した PHP+PDO+MySQLの組み合わせではSQLインジェクション攻撃で複文呼び出しが可能 にて、PDOとMySQLの組み合わせで、SQLインジェクションの文脈で複文呼び出しが可能であることを報告していましたが、その後のPHPのバージョンアップで、複文実行を禁止するオプションが追加されていましたので報告します。
対象のバージョンは以下の通りです。
  • PHP 5.5.21 以降
  • PHP 5.6.5 以降
  • 全ての PHP 7.0、7.1
前述の記事を書いた後、3大CMSの一角である Drupal に、Drupageddon (CVE-2014-3704) と呼ばれる恐ろしいSQLインジェクション脆弱性が発見されました。詳しくは、以下の記事を参照下さい。
この記事の中で、私は以下のように書きました。
実験に使用した環境はMySQLを使っていますが、SQLの複文が実行できていることになります。これは、DrupalがPDOを使っているためで、詳しくは以下のエントリを参照ください。
  • PHP+PDO+MySQLの組み合わせではSQLインジェクション攻撃で複文呼び出しが可能
すなわち、タラレバの話にはなりますが、PDOがMySQLでの複文実行を許していなければ、Drupageddonは高危険度の脆弱性には至らなかった可能性があります。少なくとも、攻撃経路はかなり限定されたはずです。
Drupalの開発陣にとっては、この事実はよほど悔しかったのかもしれません。以下のような時系列で、PDO+MySQLで複文を許さなくするオプションが提案されます。
  • 2014年10月15日 Drupageddonを修正した Druapl 7.32 がリリースされる
  • 2014年11月14日 PDOに複文を許さなくするオプションが提案される
  • 2015年 1月22日 上記を実装したPHP 5.5.21およぴ PHP 5.6.5 がリリースされる
すなわち、Drupageddonの公表からわずか3ヶ月ほどで、このオプションが実装・公開されたことになります。

どうしてこのオプションに気づいたか

私はこのオプションの存在に気がついていなかったのですが、昨日modphpallでDrupal8を動かしていたところ、下記の警告が表示されていることに気がつきました。

PHP (multiple statement disabling) 5.5.9 (more information)
PHP versions higher than 5.6.5 or 5.5.21 provide built-in SQL injection protection for mysql databases. It is recommended to update.

multiple statement disabling …ですと?
この情報から、PDO::MYSQL_ATTR_MULTI_STATEMENTSというオプションが追加されたことに気がつきました。

オプションの使い方

マニュアルから、このオプション PDO::MYSQL_ATTR_MULTI_STATEMENTS の説明を引用します。
PDO::MYSQL_ATTR_MULTI_STATEMENTS (integer)
FALSE にすると、PDO::prepare() や PDO::query() でのマルチクエリの実行を無効にします。

この定数が使えるのは、データベースハンドルを新規作成する際の driver_options 配列内だけであることに注意しましょう。

これが使えるようになった PHP のバージョンは 5.5.21 および PHP 5.6.5。

PHP: MySQL (PDO) - Manual より引用
すなわち、new PDOする際に、driver_options配列に上記を設定すればよいことになります。下記は、Drupalのソースコードを参考に、PDO::MYSQL_ATTR_MULTI_STATEMENTS が存在する場合のみ、このオプションを指定しています。
$opt = array(/* 様々な接続時オプション */);
if (defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
  $opt[PDO::MYSQL_ATTR_MULTI_STATEMENTS] = false;
}
$db = new PDO("mysql:host=DBHOSTNAME;dbname=DBNAME;charset=utf8", DBUSER, DBPASSWORD, $opt);
上記オプションが有効な状態で複文を実行しようとすると、以下のようなエラーになります。
PDO Error:SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; ...

PDO::MYSQL_ATTR_MULTI_STATEMENTS を FALSE にする効果

この設定により、SQLインジェクション攻撃で複文を使用することができなくなります。Drupageddonに効果があることは前述のとおりですが、これは現実的には意味がありません。このオプションの真意は、Drupageddonのある古いDrupalを延命させることではないでしょう。むしろ、今後、SQLの複文を使った攻撃を緩和することにあります。
複文が使えなくなると、SQLインジェクションによる改ざんがほぼできなくなると考えられますので、情報漏えいによる実害があまりなく、改ざんが主な脅威であるようなサイトには特に有力な緩和策になります。

まとめ

PDOの新オプションPDO::MYSQL_ATTR_MULTI_STATEMENTSについて紹介しました。PDOは、従来複文を許しており、SQLインジェクション攻撃を受けた場合にデータの改変など脅威が増加するなど、MySQLi等に比べて影響が大きくなっていました。PDO::MYSQL_ATTR_MULTI_STATEMENTSをFALSEに設定することで、SQLインジェクション攻撃の影響を緩和することができます。わずかな追加で緩和策となるので、このオプションの利用を推奨します。

0 件のコメント:

コメントを投稿

フォロワー

ブログ アーカイブ