FuelPHP でのセキュリティ対策(2)

FuelPHP Advent Calendar 2011 の 22日目です。

昨日は、@madmamor さんの「FuelPHPのTasks」でした。

今日は、FuelPHP でのセキュリティ対策の続きです。前回の記事をまだお読みでない場合は、「FuelPHP でのセキュリティ対策(1)」をご覧ください。


ところで、前回の「URI フィルタ」ですが、これってどういうセキュリティ上のメリットがあるんでしょうね?考えたのですが、いまいち、よくわかりません。おわかりの方いらっしゃいましたら教えてください。

SQL インジェクション対策

FuelPHP では、Query Builder (クエリビルダー) を使った場合、自動的に値がエスケープされるようになっています、とドキュメントされています。

Query Builder とは、CodeIgniter での Active Record クラスのようなやつで、以下のようなコードです。

<?php

// Will execute SELECT `name` as `the_name` FROM `users`;
$result = DB::select(array('name','the_name'))->from('users')->execute();

// Will execute SELECT * FROM `users` WHERE `id` = 1
$result = DB::select()->from('users')->where('id', '=', 1)->execute();

// Will execute INSERT INTO `users`(`name`,`email`,`password`)
// VALUES ("John Random", "john@example.com", "s0_s3cr3t")
list($insert_id, $rows_affected) = DB::insert('users')->set(array(
    'name' => 'John Random',
    'email' => 'john@example.com',
    'password' => 's0_s3cr3t',
))->execute();

要するに、SQL を生書きする DB::query() メソッドを使わなければ、自動的にエスケープされるので、Query Builder にバグがない限り SQL インジェクションは起こらないということになります。

【注意】現在の FuelPHP の PDO ドライバは、文字エンコーディングの設定に SET NAMES を使っているというバグがありますので注意してください。

FuelPHP に含まれる ORM パッケージも Query Builder を使っているため同じようにエスケープされます。

入力フィルタ

ここからは、デフォルトでは有効でないセキュリティ機能です。

入力フィルタは、$_GET、$_POST、$_COOKIE を処理する機能です。デフォルトでは何も指定されていません。

app/config/config.php

<?php
…略…
	/**
	 * Security settings
	 */
	'security' => array(
…略…
		/**
		 * This input filter can be any normal PHP function as well as 'xss_clean'
		 *
		 * WARNING: Using xss_clean will cause a performance hit.  How much is
		 * dependant on how much input data there is.
		 */
		'input_filter'  => array(),
…略…

例えば、文字エンコーディングをチェックしてみましょう。

まず、Security クラスを拡張し (「FuelPHPのcoreクラスを拡張してみる。」参照)、check_encoding() メソッドを追加します。

app/classes/security.php

<?php
…略…
	public static function check_encoding($value)
	{
		if (is_array($value))
		{
			array_map(array('Security', 'check_encoding'), $value);
			return $value;
		}
		
		if (mb_check_encoding($value, \Fuel::$encoding)) {
			return $value;
		}
		else
		{
			die('Invalid input data');
		}
	}

そして、config.php でメソッドを指定します。

app/config/config.php

<?php
…略…
	/**
	 * Security settings
	 */
	'security' => array(
…略…
		/**
		 * This input filter can be any normal PHP function as well as 'xss_clean'
		 *
		 * WARNING: Using xss_clean will cause a performance hit.  How much is
		 * dependant on how much input data there is.
		 */
		'input_filter'  => array('Security::check_encoding'),
…略…

CSRF 保護

FuelPHPCSRF 保護機能は、Cookie を使ったトークン方式です。

使うためには、保護するページの直前のページにトークンを hidden フィールドで追加します。

<input type="hidden" name="<?php echo Config::get('security.csrf_token_key'); ?>" value="<?php echo Security::fetch_token(); ?>" />

FuelPHP の Form クラスを使うと以下のように記述できます。

<?php echo Form::hidden(Config::get('security.csrf_token_key'), Security::fetch_token()); ?>

そして保護するページのコントローラのアクションで、以下のように Security::check_token() メソッドでトークンをチェックします。

<?php
…略…
		if ( ! \Security::check_token())
		{
			die('Invalid input data');
		}

なお、トークンを保存する Cookie の名前や有効期限は、config.php で変更可能です。

FuelPHP でのセキュリティ対策(3) へ続きます。


明日は、まだ誰が担当するか決まっていません!誰かお願いします。
FuelPHP Advent Calendar 2011

@akibe さんの「FuelPHPをNginxで動かしてみる」に決まりました!