なぜPHPアプリにセキュリティホールが多いのか?

第36回 MOPS:コンテクストを検出するHTMLエスケープ

この記事を読むのに必要な時間:およそ 4 分

第32回 PHPセキュリティ月間(Month of PHP Sercurity)「PHPセキュリティ月間」(MOPS - Month of PHP Security)について簡単に紹介しました。

今回もMOPS関連の話題です。MOPSではPHP関連のセキュリティ製品やセキュリティ知識の論文を募集し,11の論文が公開されました。今回はコンテクストを検出してエスケープするテンプレートエンジンについて紹介します。

MOPS Submission 02 – Context-aware HTML escaping
http://www.php-security.org/2010/05/05/mops-submission-02-context-aware-html-escaping/index.html

このテンプレートエンジンはNette Latteと呼ばれています。このテンプレートエンジンを独立して使用することもできますが,Nette Frameworkの一部として開発されています。 ホームページを見るとNette Frameworkの利用者としてチェコ首相のサイトも挙っています。チェコではかなり評判になっているフレームワークだと思われます(Nette Latteはチェコ語であると思われるので正しい発音が分かりません。ご存知の方は筆者にご連絡頂ければ幸いです)⁠

コピーライトを見ると2004年からとなっており,最近作られたフレームワークではないので既にご存知の方も多いと思います。チェコ語と英語でホームページが作られているので恐らくチェコの方が作っているフレームワークだと思われます。筆者はこのテンプレートエンジンの存在をMOPSで知ったのですが,まだ今回のこの記事を執筆するまで使ったことがありませんでした。この記事はMOPSに投稿された論文とサイトの文書から執筆しています。

コンテクストを検出するHTMLテンプレートエンジンとは?

JavaScriptインジェクションを防ぐようHTMLを記述することは簡単ではありません。HTMLの中に記述される情報はテキストやHTMLでマークアップされたテキストだけではありません。タグの属性,URL,CSS,JavaScript,JavaScriptのテキストなど,それぞれに合ったエスケープ方法でエスケープしないとJavaScriptインジェクションの原因になります。

変数を記載する場所を自動的に検出してエスケープするテンプレートエンジンは「コンテクストを検出するHTMLテンプレートエンジン(Context aware HTMLtemplate engine)⁠と呼ばれています。有名な例ではGoogleがオープンソースとして公開しているC++用のctemplateがあります。今回,紹介するNette LatteはPHPでコンテクストを検出できるテンプレートエンジンです。

Nette Latteが検出するコンテクスト

Nette Latteは以下のコンテクストを検出して適切なエスケープ処理を行います。

  • HTMLテキスト
  • "または'で囲まれたHTML属性
  • <script>または<style>で囲まれたCDATAのセクション
  • HTML属性のstyleおよびonclickなどのイベンドハンドラ
  • HTMLコメント

URLを属性値とする属性(href, src)はエスケープすべき部分(クエリ文字列パラメータ名と値)とそれ以外の部分が混在するためサポートされていないようです。

Nette Latteの利用例

どのように利用するのかは利用例を見るとすぐ分かります。

<script type="text/javascript">
var userId = {$userId};
</script>;
<p style="color: {$color};" title="{$title}">;
<a href="" onclick="return !confirm({$message});">{$desc}</a>;
</p>
<!-- Executed in: {$time} s -->;

Nette Latteのテンプレートでは各変数をそのまま出力しているように記述しますが,変数はそれぞれのコンテクストに合わせて適切な方法でエスケープされます。<script>タグの中を見るとJavaScriptの変数がクオートで囲まれていないことに気付くと思います。Nette Latteは出力されるPHP変数のデータ型に合わせてJavaScript変数を出力する便利な機能を持っています。数値型はJavaScriptの数値として,文字列型はJavaScriptの文字列として,連想配列はJavaScriptのオブジェクトリテラルとして出力されます。

Nette Latteには自動的なエスケープを停止するオプションはありません。その代わりに {!$var} と変数の前に ! を追加します。⁠Nette Latteが検出するコンテクスト」でも記載しましたが,Nette LatteはURL属性を検出しません。URLリンクは代わりに {link} マクロを使う仕様になっています。

Nette Latteのマクロ

ほかのテンプレートエンジンと同様にさまざまなマクロをサポートしています。

標準のマクロ

{$variable}
テンプレート変数の出力
{!$variable}
テンプレート変数をエスケープなしで出力
{*text comment*}
テンプレート用のコメント
{plink ...}
presenterのリンク
{link ...}
urlの生成
{if ?} ... {elseif ?} ... {/if}
<?php if (?): ?> ... <?php elseif (?): ?> ... <?php endif ?>
{foreach ?} ... {/foreach}
<?php foreach (?): ?> ... <?php endforeach ?>
{for ?} ... {/for}
<?php for (?): ?> ... <?php endfor ?>
{while ?} ... {/while}
<?php while (?): ?> ... <?php endwhile ?>
{include dir/file.phtml}
テンプレートのインクルード
{var foo => value}
テンプレート変数宣言
{default foo => value}
デフォルト値の設定
{control loginForm}
ログインフォーム
{dump $variable}
変数のダンプ

これだけでも十分な機能を持っていますが,追加のマクロも利用できるようになっています。

追加のマクロ

{=expression}
<?php echo htmlSpecialChars(expression) ?>
{!=expression}
<?php echo expression ?>
{?expression}
PHPコードを評価
{_expression}
トランスレーション
{!_expression}
エスケープ無しのトランスレーション
{ifCurrent}
{if}がアクティブリンクの場合の特別なif
{include 'dir/file.phtml'}
テンプレートの読み込み
{cache ?} ... {/cache}
キャッシュチェック
{snippet ?} ... {/snippet}
制御スニペット
{attr ?}
HTMLタグ属性の登録
{capture $var} ... {/capture}
出力バッファリングを行い$varに保存
{block | texy} ... {/block}
texy ブロック
{widget ...}
コンポーネントをレンダリング
{control ...}
widgetのエイリアス
{contentType ?}
HTTPヘッダのContent-Typeを送信
{debugbreak}
ブレークポイントの挿入

著者プロフィール

大垣靖男(おおがきやすお)

University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て,エレクトロニック・サービス・イニシアチブ有限会社を設立。
オープンソース製品は比較的古くから利用し,Linuxは0.9xのころから利用している。オープンソースシステム開発への参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトでは,PostgreSQLモジュールのメンテナンスを担当している。

URLhttp://blog.ohgaki.net/

著書

コメント

コメントの記入