- 2007/6/15 金曜日 2:41:55
- perl
TTでのXSS対策としては下記の2つの方法がまずは考えられます。
1. [% data | html %]のようにFILTERをすべての変数出力部分に使う
2. Template::Stash::EscapeHTMLを使って自動的に全ての変数出力をEscapeする
1は毎回”| html”と書くことになるので、間違いが置きやすいので2を使うことが多いのですが
システム側からescapeしないで出力したいとか、INCLUDEで変数を渡したいとかいうときに問題がでてしまう。
INCLUDEの話はどういうことかというと
たとえば、ヘッダーをheader.ttというファイルにまとめて共有で使っており
渡された変数を用いてタイトルを構成するときなんかがあったとする。
(ちなみにMETAだと変数は渡せない)
content.tt
[% INCLUDE header.tt
title = title_html
%]
header.tt
<html>
<head>
<title>[% title %]</title>
</head>
<body>
まぁこんな構成で下記のように呼び出したとする
#!/usr/bin/perl
use strict;
use Template;
use Template::Stash::EscapeHTML;
my %var = (
title_html => ‘<html>’,
);
my $template = Template->new({
STASH => Template::Stash::EscapeHTML->new(),
});
$template->process(‘content.tt’, \%var);
そうするとこれの実行結果は
<html> <head> <title>&lt;html&gt;</title> </head> <body>
となってしまう。
これは意図した結果ではなく正しくは
<html> <head> <title><html></title> </head> <body>
となってほしいわけですね。
二重にEscapeされてしまう。
これは、STASHのgetは変数の代入の時にも呼ばれている影響です。
代入する度にEscapeされるわけでINCLUDEしなくても単純に
[% title = title_html %]
[% title %]
このようにしていてもやはり同じ問題は起きてしまう。
というわけで、escapeしないことを明示的に指示することをしたい。
こうなってくると最初の1の方法の”| html”でも同じじゃないかと思われるかもしれないが
Order allow, deny
より
Order deny, allow
(Apache用語)
のほうがセキュリティ上は好ましいし、何よりコード量も減る。
で、Template::Stash::EscapeHTMLByCaseってのを作ってみた。
命名はまずいかもしれない。
package Template::Stash::EscapeHTMLByCase; use strict; use Template::Config; use base ($Template::Config::STASH); our $VERSION = '0.01'; sub get { my ($self, @args) = @_; if (is_raw(@args)) { @args = strip_raw_specifier(@args); return $self->SUPER::get(@args); } my ($var) = $self->SUPER::get(@args); unless (ref($var)) { return html_filter($var); } return $var; } sub html_filter { my $text = shift; for ($text) { s/&/&/g; s/</</g; s/>/>/g; s/"/"/g; } return $text; } sub is_raw { my @args = @_; if (ref $args[0] ne 'ARRAY') { return 0; } if ($args[0]->[0] ne 'RAW') { return 0; } return 1; } sub strip_raw_specifier { my @args = @_; splice @{$args[0]}, 0, 2; return @args; } 1;
使い方はこんな感じにRAWを最初につけてあげる。
content_kai.tt
[% INCLUDE header.tt
title = RAW.title_html
%]
そうすると期待通りに下記の文字列が出力される。
<html> <head> <title><html></title> </head> <body>
と、こんなことをやってみましたが皆さんはこんな状況をどうしてるもんなんでしょ
それ、TemplateToolkitの標準機能で解決できるよ。とかありそうだけど・・・。
なかったらCPANに上げてみたいなぁ(まだCPAN Authorじゃない・・・)とか。
コメント:0
トラックバック:1
- この記事のトラックバック URL
- https://blog.everqueue.com/chiba/2007/06/15/12/trackback/
- トラックバックの送信元リスト
- Template::Stash::EscapeHTMLByCase(TTでXSS対策) - へぼい日記 より