【注意喚起】CodeIgniter 1.7.2 Formヘルパーの脆弱性
(2011/04/11 追記) 当初記載されていた対策の修正および CodeIgniter 2.0.0 以降での対策を追記しました。
問題の所在
CodeIgniter の Formヘルパーにはフィールドの値を表示するための set_value() が用意されていますが、set_value() で同じフィールドを 2回目以上表示すると 2回目以降は文字参照に変換されず XSS脆弱性になる可能性があります。
確認ページで、入力値を表示し、隠しフィールドに値を埋め込み POST させるような実装の場合に、この脆弱性に該当します。
原因
CodeIgniter の Formヘルパーの form_prep() に問題があります。Formヘルパーは内部的に form_prep() を呼び出していますが、それが影響しています。
サンプルコード
controllers/form.php
<?php class Form extends Controller { function Form() { parent::Controller(); $this->load->library('form_validation'); $this->form_validation->set_rules('status', 'Status', 'trim|required|max_length[140]'); } function index() { $this->form_validation->run(); $this->load->view('form1_view'); } } /* End of file form.php */ /* Location: ./system/application/controllers/form.php */
views/form1_view.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Form_validation Sample</title> </head> <body> <?php echo validation_errors(); ?> <form action="" method="post"> What are you doing? <input type="text" name="status" value="<?php echo set_value('status'); ?>" /> <input type="submit" value="Update" /> </form> <?php echo set_value('status'); ?> </body> </html>
set_value('status') で statusフィールドに入力された値を表示していますが、下の表示ではエスケープされないため XSS が可能になります。
フォームに、
<s>test</s>
と入力した場合、出力される HTML は、以下のようになります。
<body> <form action="" method="post"> What are you doing? <input type="text" name="status" value="<s>test</s>" /> <input type="submit" value="Update" /> </form> <s>test</s> </body>
対策
(2011/04/11 追記)
helpers/form_helper.php を以下のように変更します。
--- system/helpers/form_helper.php.orig 2010-07-12 22:21:54.000000000 +0900 +++ system/helpers/form_helper.php 2011-04-11 13:40:49.647917245 +0900 @@ -617,7 +617,7 @@ // @todo need to figure out a way to namespace this so // that we know the *exact* field and not just one with // the same name - if (isset($prepped_fields[$field_name])) + if (isset($prepped_fields[$field_name]) && $prepped_fields[$field_name] === $str) { return $str; }
(2011/04/11 追記) 当初記載されていた以下の対策は、配列の扱いに問題がありました。ただし、この対策でも脆弱性は修正されます。
--- form_helper.php.orig 2009-07-18 05:25:13.000000000 +0900 +++ form_helper.php 2010-03-15 13:28:09.000000000 +0900 @@ -619,7 +619,7 @@ // the same name if (isset($prepped_fields[$field_name])) { - return $str; + return $prepped_fields[$field_name]; } $str = htmlspecialchars($str);
(2011/04/11 追記) CodeIgniter 2.0.0 以降は、以下のように変更します。
--- a/system/helpers/form_helper.php +++ b/system/helpers/form_helper.php @@ -631,7 +631,7 @@ if ( ! function_exists('form_prep')) // @todo need to figure out a way to namespace this so // that we know the *exact* field and not just one with // the same name - if (isset($prepped_fields[$field_name])) + if (isset($prepped_fields[$field_name]) && $prepped_fields[$field_name] === $str) { return $str; } @@ -643,7 +643,7 @@ if ( ! function_exists('form_prep')) if ($field_name != '') { - $prepped_fields[$field_name] = $field_name; + $prepped_fields[$field_name] = $str; } return $str;