symfony のエスケープ処理
森川です。
今回は symfony のエスケープ処理について、きちんと解説したいと思います。
まず、symfony のデフォルトでは変数を出力するときのエスケープが無効になっています。
つまりデフォルトの状態だとユーザが入力した変数を出力している場合、危険性があるかもしれないということです。
上記のスクリプトでは、$sf_params->get('name') が脆弱性アリな状態となっています。
これは非常にまずいので、エスケープを有効にしてあげましょう。そのためには、apps/[name]/config/settings.yml を編集します。
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 として指定する場合は以下のようなヘルパーを用意します。
symfony本体のhelper/EscapingHelper.php を見ればよくわかると思います。
ここからはTIPSになりますが、ESC_ENTITIESでエスケープする場合、オブジェクトや配列の取り扱いが少々ややこしくなるので、注意が必要です。
どういうことかというと、テンプレート内で使用するすべての変数がsymfony本体の view/escaper/sfOutputEscaper*.class.php で定義されているオブジェクトに変わってしまうのです。
一番困るのが、先ほどのスクリプトでもあった、getメソッドです。たとえば、以下のソースを見て下さい。
このソースでは何も指定されていなければ、「空ですよ」という文字列が出てくることを期待しますが、これが出てこないのです。
なぜかといえば、sfOutputEscaperObject.class.php の get 関数が呼ばれてしまい、 sf_params(sfParameterHolder)のget関数は呼ばれないのです。
たとえば、以下のように書き換えることができます。
このように get 関数を使用する場合は注意してください。それと同様に in_array などの関数を使用すると、配列型ではない旨のエラーが出たりしてしまいます。
エスケープ専用のオブジェクトになっている、ということを念頭に入れておけば、問題が起きてもすぐに解決できるようになると思います。
今回は symfony のエスケープ処理について、きちんと解説したいと思います。
まず、symfony のデフォルトでは変数を出力するときのエスケープが無効になっています。
つまりデフォルトの状態だとユーザが入力した変数を出力している場合、危険性があるかもしれないということです。
echo $sf_params->get('name') echo form_tag('test') echo input_tag('name') echo submit_tag('テスト') - </form>
上記のスクリプトでは、$sf_params->get('name') が脆弱性アリな状態となっています。
これは非常にまずいので、エスケープを有効にしてあげましょう。そのためには、apps/[name]/config/settings.yml を編集します。
- all:
.settings: escaping_strategy: both 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 として指定する場合は以下のようなヘルパーを用意します。
- function
my_escaping_func($value) - {
// 必要な処理を $value に加えて return する - }
- define('MY_ESC')
symfony本体のhelper/EscapingHelper.php を見ればよくわかると思います。
ここからはTIPSになりますが、ESC_ENTITIESでエスケープする場合、オブジェクトや配列の取り扱いが少々ややこしくなるので、注意が必要です。
どういうことかというと、テンプレート内で使用するすべての変数がsymfony本体の view/escaper/sfOutputEscaper*.class.php で定義されているオブジェクトに変わってしまうのです。
一番困るのが、先ほどのスクリプトでもあった、getメソッドです。たとえば、以下のソースを見て下さい。
echo $sf_params->get('name', '空ですよ')
このソースでは何も指定されていなければ、「空ですよ」という文字列が出てくることを期待しますが、これが出てこないのです。
なぜかといえば、sfOutputEscaperObject.class.php の get 関数が呼ばれてしまい、 sf_params(sfParameterHolder)のget関数は呼ばれないのです。
たとえば、以下のように書き換えることができます。
echo $sf_request->getParameter('name', '空ですよ') echo $sf_data->getRaw('sf_params')->get('name', '空ですよ')
このように get 関数を使用する場合は注意してください。それと同様に in_array などの関数を使用すると、配列型ではない旨のエラーが出たりしてしまいます。
エスケープ専用のオブジェクトになっている、ということを念頭に入れておけば、問題が起きてもすぐに解決できるようになると思います。
トラックバックURI
最近の記事
システム開発エンジニア募集! [2012年02月03日 : 小林有佳]
OpenVPNで細々便利な設定 [2012年01月31日 : 門脇優児]
【iOS】Viewの開発・デバッグに役立つ色々 [2012年01月23日 : 中川善樹]
PHPDocumentorの利用方法まとめ [2012年01月19日 : 笹亀弘]
Google Chart Toolsを使ってサイトマップを描こう! [2011年12月21日 : 志田仁美]
stumpwm設定v2 [2011年12月19日 : 門脇優児]
Mashup Awards 7の授賞式が行われました [2011年12月16日 : 中川善樹]
社員旅行に行きました [2011年12月12日 : 大橋寛子]
iCloud風のアイコンを作成する(Fireworks) [2011年12月07日 : 和田記光]
iScroll4でネイティブに近いスマホ向けHTMLページを作成する [2011年12月02日 : 松田惇]













コメントフォーム