アシアルの中の人が技術と思いのたけをつづるブログ

symfony のエスケープ処理

タグ [  Tech  symfony  エスケープ  ]
森川です。

今回は symfony のエスケープ処理について、きちんと解説したいと思います。

まず、symfony のデフォルトでは変数を出力するときのエスケープが無効になっています。

つまりデフォルトの状態だとユーザが入力した変数を出力している場合、危険性があるかもしれないということです。

  1. <?php echo $sf_params->get('name') ?>
  2.  
  3. <?php echo form_tag('test') ?>
  4. <?php echo input_tag('name') ?>
  5. <?php echo submit_tag('テスト') ?>
  6. </form>

上記のスクリプトでは、$sf_params->get('name') が脆弱性アリな状態となっています。

これは非常にまずいので、エスケープを有効にしてあげましょう。そのためには、apps/[name]/config/settings.yml を編集します。

  1. all:
  2.   .settings:
  3.     escaping_strategy: both
  4.     escaping_method: ESC_ENTITIES

21行目、41行目、55,6行目をコメントアウトして(symfony 1.0.13の場合)、さらに55行目の bc を both にします。

こうしてあげると、スクリプト自体を変更しなくてもきちんとエスケープされるようになります。

とりあえずめでたしめでたし、と言いたいところなのですが、今回はここからが本題です。

エスケープされたとはいえ、なぜエスケープされるのか、といったことがいまいちよくわかりませんし、escaping_strategy,methodの意味もいまいちよくわかりません。ということで、それぞれの意味を簡単に説明したいと思います。

まずは、escaping_strategy についてです。この値はどの変数をエスケープするのか、ということを設定します。

設定値として取り得る値は bc both on off の4種類がありますが、それぞれ違いがあります。

違いを説明する前に、テンプレート内で使用できる変数を2種類に分けます。一つは$var_name のような形式で、もう一つは $sf_data->get('var_name') の形式です。4種類での違いは以下のようになります。

・bc: $var_name はエスケープされない、$sf_data->get('var_name') はエスケープされる
・both: 両方ともエスケープされる
・on: $var_name は使用できない、$sf_data->get('var_name')はエスケープされる
・off: $var_name はエスケープされない、$sf_data は使用できない

ちなみに、both、off以外を使用することはまずないと個人的には思っています。なので、あんまりこの説明も意味がないかもしれません(まぁ簡単なTIPSだと思って下さい)。。。もっと深く知りたい方は symfony の view/sfPHPView.php を見るとよいと思います。


次の escaping_method ですが、こちらはエスケープの方法を指定します。

取り得る値は ESC_RAW、ESC_ENTITIES、ESC_JS、ESC_JS_NO_ENTITIES の4種類です。それぞれの違いは以下のようになります。

・ESC_RAW:何もエスケープしません。
・ESC_ENTITIES: htmlentities関数を使用してエスケープします。
・ESC_JS: htmlentities関数でエスケープした後に、addcslashesでエスケープされます。
・ESC_JS_NO_ENTITIES: addcslashesでのみエスケープされます。

addcslashes では JavaScript で使用するときにエスケープする必要がある文字をエスケープします。

ちなみに、MY_ESC と escaping_method として指定する場合は以下のようなヘルパーを用意します。

  1. <?php
  2. function my_escaping_func($value)
  3. {
  4.   // 必要な処理を $value に加えて return する
  5. }
  6. define('MY_ESC')

symfony本体のhelper/EscapingHelper.php を見ればよくわかると思います。

ここからはTIPSになりますが、ESC_ENTITIESでエスケープする場合、オブジェクトや配列の取り扱いが少々ややこしくなるので、注意が必要です。

どういうことかというと、テンプレート内で使用するすべての変数がsymfony本体の view/escaper/sfOutputEscaper*.class.php で定義されているオブジェクトに変わってしまうのです。

一番困るのが、先ほどのスクリプトでもあった、getメソッドです。たとえば、以下のソースを見て下さい。

  1. <?php echo $sf_params->get('name', '空ですよ') ?>

このソースでは何も指定されていなければ、「空ですよ」という文字列が出てくることを期待しますが、これが出てこないのです。

なぜかといえば、sfOutputEscaperObject.class.php の get 関数が呼ばれてしまい、 sf_params(sfParameterHolder)のget関数は呼ばれないのです。

たとえば、以下のように書き換えることができます。

  1. <?php echo $sf_request->getParameter('name', '空ですよ') ?>
  2. <?php echo $sf_data->getRaw('sf_params')->get('name', '空ですよ') ?>

このように get 関数を使用する場合は注意してください。それと同様に in_array などの関数を使用すると、配列型ではない旨のエラーが出たりしてしまいます。

エスケープ専用のオブジェクトになっている、ということを念頭に入れておけば、問題が起きてもすぐに解決できるようになると思います。

コメントフォーム

認証
captcha_key
 

トラックバック