Perl have nice feature called taint mode which helps developers to write more secure code by forcing them to carefully verify all input. However it doesn't help to prevent certain type of security vulnerabilities like XSS because this type of security vulnerabilities happen when developer doesn't verify and escape output. On first look it seems that taint mode is useless to force checking of output. But I was still thinking if it is really useless in this case. And I've got this idea: how about implementing an additional layer between web applications and its clients which would assure that tainted data cannot pass into web application's output. As result of this meditation I've come up with this merely proof-of-concept implementation which works with Template::Toolkit based applications.

package Template::Secure; use strict; use warnings; use base qw(Template); use Carp; use Scalar::Util qw(tainted); # simplified version of Template's process method which only supports # output to STDOUT sub process { my ($self, $template, $vars) = @_; my $output = ''; my $ret = $self->SUPER::process($template, $vars, \$output); if(tainted $output) { croak("Insecure dependency in Template::Secure->process()"); } print $output; return $ret; }

This is almost drop-in replacement module for Template module which will complain if it notices any tainted data in output. Another missing piece is convenient plugin for Template which would implement HTML/URL escaping in output and untaint escaped strings at same time. Template toolkit provides two plugins useful to do escaping of strings in HTML: Template::Plugin::URL and Template::Plugin::HTML. They only have to be slighly changed to untaint escaped strings.

# a bit hacky way to redefine subs without modifying sources; this # code can be put directly into Template::Secure module { require Template::Plugin::URL; require Template::Plugin::HTML; no warnings 'redefine'; my $url_escape_sub = \&Template::Plugin::URL::escape; *Template::Plugin::URL::escape = sub { my $ret = $url_escape_sub->(@_); $ret =~ /(.*)/; # untaints string return $1; }; my $html_escape_sub = \&Template::Plugin::HTML::escape; *Template::Plugin::HTML::escape = sub { my $ret = $html_escape_sub->(@_); $ret =~ /(.*)/; # untaints string return $1; }; }

Now example application: nearly hello world :).

#!/usr/bin/perl -T # First version which has XSS hole and doesn't work thanks to taint # checks in Template::Secure use strict; use warnings; use CGI; use Template::Secure; my $query = CGI->new; my $name = $query->param('name') || 'World'; my $tt = Template::Secure->new; print $query->header; $tt->process(\*DATA, { name => $name }) || die $tt->error(), "\n"; __END__ <html> <head> <title>Sample program</title> </head> <body> Hello, [% name %]! </body> </html>
#!/usr/bin/perl -T # Second version which is XSS free use strict; use warnings; use CGI; use Template::Secure; my $query = CGI->new; my $name = $query->param('name') || 'World'; my $tt = Template::Secure->new; print $query->header; $tt->process(\*DATA, { name => $name }) || die $tt->error(), "\n"; __END__ [% USE HTML %] <html> <head> <title>Sample program</title> </head> <body> Hello, [% HTML.escape(name) %]! </body> </html>

P.S. Note that it is merely proof-of-concept just to show the idea. There are probably some missing pieces (for example real implementation should untaint templates which are read by Template Toolkit from filesystem). And I'm sure same idea can be ported to other templating modules.

Ilya Martynov,
Quality Perl Programming and Unix Support UK managed @ offshore prices -
Personal website -