FuelPHP tips Fuelのセキュリティ機能2
・出力フィルタ
 ・URIフィルタ
 ・SQL文の自動エスケープ
・入力フィルタ
・XSSフィルタ
・バリデーション(検証)
・CSRF保護
はい、Fuelのセキュリティ機能1で説明できなかった残り4つ行きます。
微妙に順番が変わってるのは気にしない。
1. 入力フィルタ
入力フィルタとは、スーパーグローバル変数の内
$_POST
$_GET
$_COOKIE
この3つを処理する機能です。
フォームからの入力やクッキーの値などに独自のフィルタをかける事が可能です。
デフォルトではなにも設定されておらず全く機能しません。
| 1 2 3 4 5 6 | /**  * Security settings  */ 'security' => array(     'input_filter' => array(), ) | 
ほら、coreの方のconfig見ても何もないでしょ?array()の中が空でしょ?
この中には自分で作った関数を入れる事ができます。(使う時はcoreじゃなくappの方を編集しましょう。)
例えば、出力フィルタやURIフィルタで使用されている「htmlentities」を指定できたりします。(公式ドキュメント引用)
このブログの住人が参考にしている書籍では文字エンコーディングのフィルタを用意していましたね。
指定の仕方は例えば次のようになります。
| 1 2 3 4 5 6 | /**  * Security settings  */ 'security' => array(     'input_filter' => array('Ore::rule'), ) | 
Oreクラスのruleメソッドを指定してます。
でもって次がそのクラスです。配置は app/class/ore.php
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php class Ore { 	public static function rule($value) 	{            /*ここでフィルタのルールを書いてやるといいと思うんだ*/            /*例えば、$valueの文字エンコードを調べたり*/            /*改行やタブはいいとしても、Delete等の普通は入力できない制御文字のチェックをするといいです*/            $foo = rand();            if( $foo % 100 != 0)               return $value;            else die('素晴らしく運がないなぁ君はぁ'); 	} } | 
ランダムで100分の1の確率で処理を受け付ける的な感じになってます。
サンプルです。あくまでサンプルです。
普通だったら文字エンコーディングのチェックとかすると思います。
なぜこの入力フィルタがデフォルトで有効になってないかというと、公式ドキュメントが
「そんなことより出力フィルタが先だ」って言ってた気がする。
最終的に出力フィルタで全部エスケープするよ。って事だろうか。
2. XSSフィルタ
さぁ、なんて読むだろうか。
クロスサイトスクリプティングと読むらしい。
ちなみに、Fuelのセキュリティ機能1の出力フィルタでやった危ないサンプルがあったけど、あれがXSSです。
出力フィルタで使用しているhtmlentitiesだけでは対処が難しい場合、
Securityクラスが用意している「xss_clean()」っていう関数を使えばいいらしいです。
htmLawedというライブラリを使用してるらしいです。
なんでもかんでもタグ文字とかをエスケープするのではなく、危険なコードを安全なものに直したりするらしいんですがショウジキヨクワカラナイシシュツリョクフィルタニタヨリッキリナノデパスデオネガイシマス。
一応サンプル(Viewは割愛)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php class Controller_Test extends Controller { 	public function action_index() 	{ 		//以下サンプル3つ。 		$data['a'] ='<SCRIPT>alert("(・ω・)")</SCRIPT>'; 		$data['a'] = Security::xss_clean($data['a']); 		$data['b'] ='<div>これは大丈夫</div>'; 		$data['b'] = Security::xss_clean($data['b']); 		$data['c'] ='<A HREF="javascript:document.location='http://www.google.com/'">XSS</A>'; 		$data['c'] = Security::xss_clean($data['c']);                 //出力フィルタをfalseにしておこう 		return View::forge('sec_test_view.smarty',$data,false); 	} } | 
各3つのサンプルの2行目、xss_clean()の行をコメントアウトしたりして動作を確認できます。
1つ目はスクリプト実行によりアラートが出てきます。
フィルタに通すと「<SCRIPT></SCRIPT>」を取り除いてくれます。
2つ目はそのまま表示されます。全てのタグを取り除くわけではないようです。
3つ目はフィルタを通すと「javascript」の前に「deny:」を付けて無効化(?)してくれたりします。
「<A HREF=・・・」は「<a href=・・・」とか小文字に直してくれて残してくれます。
FuelPHPの公式ドキュメントには、「パフォーマンスの理由」により個別の変数に対して使用することを推奨しているようです。
それよりもなによりも出力フィルタを優先すべきだと言ってるので、出力フィルタをオフにしないように心がけたい。
3. バリデーション (検証)
バリデーションは、あらかじめ作って置いたルールに基づき変数を検証することです。
「ユーザー名は○文字以下まで」
「パスワードは○文字以上○文字以下」
などです。
使い方はこちらを参照してください。
→チュートリアル フォームの作成とDBの使い方
4.CSRF保護
このCSRF、クロスサイトリクエストフォージェリって言います。
XSSと似てますが違います。
CSRFの恐怖はこちらを参照→Wikipedia:クロスサイトリクエストフォージェリ
このCSRFの対策とし
1.ページ作成時に次の2のためのトークンを生成
2.form送信の時にCSRF対策用のトークン(hiddenでおk)を一緒に送信
3.送られてきたトークンをチェックし有効ならそのまま、無効ならアウトォォォ!
では、1のコードから2の送信
| 1 2 3 4 5 | <form 〜〜割愛〜〜> <?php echo Form::hidden(Config::get('security.csrf_token_key'),                Security::fetch_token()); ?> <input 割愛〜〜> </form> | 
Viewで作ってます。面倒なんで。
Config::get(〜〜〜)で「security」の「csrf_token_key」の値を取得します。
デフォルトでは「fuel_csrf_token」という文字列になってます。
Security::fetch_token()でトークンを生成しています。
そして、各フォームの値と一緒に送信します。
そして、次の3のコードでチェック
| 1 2 3 | if( Security::check_token() == false )     echo "トークンが一致しません。"; else "トークンが一致。有効なリクエストだぁ"; | 
メッセージが長くてうざいけど、チェックする処理自体は非常に短いです。
このCSRF保護機能ですが、中身の実装がやや怪しいらしいです(暗号論的疑似乱数生成とか)
バージョンアップで強化されていくことを願いましょう。
これで一応終了。
もうセキュリティって言葉ってなんだ?
っていうゲシュタルト崩壊が起きてきそうです。