symfonyフレームワークのセキュリティ
このblogでは、主にjobeet*1という、symfony*2チュートリアルに沿ってsymfony自体や、PHPとその周辺について勉強を進めていく中で、気になったこと、調べたことをまとめていこうと思います。
途中まで進めているので、しばらくはメモを見て思い出しながら書いていこうと思います。
今回はsymfonyでのセキュリティについて。
webアプリを作る上で、セキュリティは切っても切れない存在だと思います。
アプリケーションフレームワークに触れるのは始めてだったのですが、jobeetを始める前から
とぼんやり考えてました。
そんな感じでjobeetをはじめたわけです。
symfonyでは、デフォルトでXSSとCSRF対策をしてくれます。*3
1日目に書いてあって、関心。いわくjobeetは
「実際のアプリケーションでは、バリデーションと適切なエラーハンドリングを追加するのを忘れないでください」
や
「読者の練習のため、セキュリティについては考慮していません」
や
「もちろんテストの記述は必要になります」
なんてことは言わない、実用的なチュートリアルなんです。
XSSって?
XSS(クロスサイトスクリプティング)*4とは、
ウェブアプリへの入力をきちんとエスケープしないでHTMLに出力してしまうことで、入力に含まれているタグがそのままHTMLとして解釈されてしまうという脆弱性。
簡単な例として、
<div> 名前 : <?php echo $_POST['user'] ?></div>
という風にPOSTの変数を直接出力してしまうと、
<script>while(1){ alert( 'test' ); }</script>
のようにJavascriptが入力された時にそのまま実行されて、大変なことになります。
こんな感じで、任意のスクリプトが実行できてしまうので、XSSを利用した攻撃はわりとこわい。
wikiによると、XSSを利用することで
- クッキーの値を取得あるいは設定することにより、セッションハイジャックする
- 強制的なページ遷移を起こさせ、クロスサイトリクエストフォージェリ対策を回避する(取得したクッキーを攻撃者側でそのまま利用できない場合に用いられる手法)
- ページ全体を置き換えることにより、偽のページを作り出す(典型的にはフィッシングに用いられる)
- フォームの送信先を置換することにより、入力を第三者サイトに送信するよう仕向ける
といった攻撃が成立するらしい。
対策
XSSの対策は、出力値のエスケープを適切に施すことらしいです。
(らしいですというのは、自分がまだ「適切に」というのを把握してきれてないから)
wikiによると、
- HTMLの実体参照を用い、& を & に、< を < に、> を > に、" を " に、それぞれ置換する。(サニタイジング*5)
- タグの属性値は必ず "〜" (ダブルクオート)で括る。また属性値中のエスケープを忘れない。例:
だし、PHPとWebアプリケーションのセキュリティについてのメモ*6によると、
htmlspecialchars()を通して出力すれば、ほとんどのXSSは回避できます。
とのこと。ほとんど、ってなに?って感じだけれど。
この辺は全体を把握できるようにならんといかんですね。
じゃあ、symfonyはなにをしてくれるの?
symfonyのescape処理については、こんなページを見つけました。
symfony のエスケープ処理 - アシアルブログ
出力値のescapingの設定は、apps/frontend/config/settings.yml をいじることでできます。
escaping_methodでescapeの方法を指定します。デフォルトではESC_SPECIALCHARSに設定されてました。
それぞれの設定は
- ESC_RAW: 値のエスケープを行わない
- ESC_SPECIALCHARS: 入力に対して、htmlspecialchars()でエスケープを行う
- ESC_ENTITIES: ENT_QUOTES引数付き*7のhtmlentities()でエスケープを行う
- ESC_JS: HTMLとして使用されるであろうJavaScript文字列をエスケープする。
- ESC_JS_NO_ENTITIES: JavaScritp文字列をエスケープするが、エンティティは付加しない。
記事が少し古いのが気になりますが、エスケープに使われているhtmlspecialchars()とhtmlentities()の違いについては以下のページがわかりやすいかと。
http://d.hatena.ne.jp/teracc/20070415
肝心のエスケープはlib/vendor/symfony/lib/helper/EscapingHelper.phpで定義された関数で行われていて、escaping_methodにESC_SPECIALCHARSが指定されている場合は、55行目の
function esc_specialchars($value) { // Numbers and boolean values get turned into strings which can cause problems // with type comparisons (e.g. === or is_int() etc). return is_string($value) ? htmlspecialchars($value, ENT_QUOTES, sfConfig::get('sf_charset')) : $value; }
で行われてるっぽい。ちゃんとhtmlspecialchars()が使われてますね。
で、これがどこで呼び出されてるかまではコード追えませんでした。
あとで、もう少し詳しくsymfonyのコードを追って見ようと思います。
ちら見した感じだと、このあたりを読めばescapingの流れがつかめるかなと予想。
ちなみにtemplateで利用できる変数$sf_dataはsfOutputEscaperArrayDecoratorクラスのインスタンスみたいですね。
疑問
これって、入力したユーザ自身が攻撃の被害を受けるっぽいけど、自分で自分を攻撃するなんてことはないはず。
だとしたら、実際の攻撃が行われるシチュエーションってどんな感じなんだろう?
ぱっと思いついたのは、該当箇所がGETの値を使ってるなら、うしろにデータのついたURLを踏ませれば、自分以外の人をターゲットにできるかなー、といった感じ。
意外とXSSについて調べるだけで時間がかかってしまったので、CSRFについてはあとでまとめようと思います。
なんとなくまとめてみて、
フレームワークに任せっきりじゃなくて、全体を把握した上で、フレームワークでなに対策を”どういうふうに”してくれてて、何はしてないのかをきちんと把握する
のが大事っぽいな、という結論に。
まだまだセキュリティに関する知識は足りないのでアレですが、ぼちぼち勉強していかないとなぁ。
*1:http://www.symfony-project.org/jobeet/1_4/Propel/ja/
*2:PHP5向けのウェブアプリケーションフレームワーク
*3:http://www.symfony-project.org/jobeet/1_4/Propel/ja/01
*4:http://ja.wikipedia.org/wiki/XSS
*5:「サニタイズ言うな」てのがあるらしい、http://takagi-hiromitsu.jp/diary/20051227.html#p02
*6:http://www.asahi-net.or.jp/~wv7y-kmr/memo/php_security.html
*7:シングルクォーテーションも変換する