From b84a55c67b0f36170a5d3fcc3b50bc3333d449dc Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 20 Aug 2024 00:12:21 +0000 Subject: [PATCH] Bug 22223: Add filter to make item URLs safe in template output This change adds a "safe_url" filter which takes a text input and returns a Perl URL object which stringifies to a safe URL. This change is only needed in the OPAC as the staff interface handles the item URL display using Javascript not Template Toolkit. 0. Apply patch and koha-plack --restart kohadev 1. Create an item for a record using the following URL https://koha-community.org?url=https%3A%2F%2Fkoha-community.org 2. Go to the OPAC for that record and verify that the URL is not double-escaped 3. Create a malicious payload (talk to QA/security team for this if necessary) 4. Note that the malicious payload is escaped 5. prove t/Koha/Plugins/SafeURL.t 6. Celebrate! Signed-off-by: Lucas Gass --- Koha/Template/Plugin/SafeURL.pm | 66 +++++++++++++++++++ .../bootstrap/en/modules/opac-detail.tt | 5 +- t/Koha/Plugins/SafeURL.t | 57 ++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 Koha/Template/Plugin/SafeURL.pm create mode 100755 t/Koha/Plugins/SafeURL.t diff --git a/Koha/Template/Plugin/SafeURL.pm b/Koha/Template/Plugin/SafeURL.pm new file mode 100644 index 0000000000..0a8847dd64 --- /dev/null +++ b/Koha/Template/Plugin/SafeURL.pm @@ -0,0 +1,66 @@ +package Koha::Template::Plugin::SafeURL; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; +use URI; +use base 'Template::Plugin::Filter'; + +sub init { + my $self = shift; + my $name = 'safe_url'; + $self->{_DYNAMIC} = 1; + $self->install_filter($name); + return $self; +} + +sub filter { + my ( $self, $text, $args, $config ) = @_; + my $uri = URI->new($text); + if ($uri) { + return $uri; + } + + #NOTE: If it isn't a real URL, just return a safe fragment + return '#'; +} + +1; + +=head1 NAME + +Koha::Template::Plugin::SafeURL - TT Plugin for filtering whole URLs + +=head1 SYNOPSIS + +[% USE SafeURL %] + +[% $url | safe_url %] + +This filter parses the text as a URL and returns the object which +is stringified in a safe format. + +=head1 METHODS + +=head2 init + +This method installs the filter name and declares it as a dynamic filter + +=head2 filter + +Returns a stringified version of a Perl URL object + +=cut diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt index 7dd44416f5..f88db51c2f 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt @@ -7,6 +7,7 @@ [% USE TablesSettings %] [% USE AuthorisedValues %] [% USE KohaPlugins %] +[% USE SafeURL %] [% SET TagsShowEnabled = ( ( Koha.Preference( 'TagsEnabled' ) == 1 ) && TagsShowOnDetail ) %] [% SET TagsInputEnabled = ( ( Koha.Preference( 'opacuserlogin' ) == 1 ) && ( Koha.Preference( 'TagsEnabled' ) == 1 ) && TagsInputOnDetail ) %] [% SET CoverImagePlugins = KohaPlugins.get_plugins_opac_cover_images %] @@ -1362,14 +1363,14 @@ [% IF trackclicks == 'track' || trackclicks == 'anonymous' %] [% uri | html %] [% ELSE %] - [% uri | html %] + [% uri | html %] [% END %] [% END %] [% ELSE %] [% IF trackclicks == 'track' || trackclicks == 'anonymous' %] [% ELSE %] - + [% END %] [% IF Koha.Preference('URLLinkText') %][% Koha.Preference('URLLinkText') | html %][% ELSE %]Link to resource[% END %] diff --git a/t/Koha/Plugins/SafeURL.t b/t/Koha/Plugins/SafeURL.t new file mode 100755 index 0000000000..ae0cf40d05 --- /dev/null +++ b/t/Koha/Plugins/SafeURL.t @@ -0,0 +1,57 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 2; +use Template; + +subtest 'test double-encoding prevention' => sub { + plan tests => 1; + my $template = Template->new( + { + PLUGIN_BASE => 'Koha::Template::Plugin', + } + ); + + my $tt = <process( \$tt, {}, \$output ); + is( $output, 'http://koha-community.org?url=https%3A%2F%2Fkoha-community.org', 'URL is not double-encoded' ); +}; + +subtest 'double quotes are escaped' => sub { + plan tests => 1; + my $template = Template->new( + { + PLUGIN_BASE => 'Koha::Template::Plugin', + } + ); + + my $tt = <process( \$tt, {}, \$output ); + is( $output, 'http://koha-community.org?url=https%3A%2F%2Fkoha-community.org%22', 'double quotes are escaped' ); +}; -- 2.39.2