From c6ef2aba6bf93b3f17b57b384859edee54f99a72 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 1 Aug 2023 06:56:23 +0000 Subject: [PATCH] Bug 34369: Require CSRF token for updating system preferences This patch adds the requirements that updating a system preference requires a CSRF token. (Also, adding and deleting local system preferences.) 0. Apply patch 1. koha-plack --reload kohadev 2. Add local system preference 3. Update local system preference 4. Delete local system preference 5. Update normal system preference 6. Note no errors Signed-off-by: Jonathan Druart Signed-off-by: Marcel de Rooy Signed-off-by: Tomas Cohen Arazi --- admin/preferences.pl | 3 ++- admin/systempreferences.pl | 5 ++++- .../prog/en/modules/admin/preferences.tt | 1 + .../prog/en/modules/admin/systempreferences.tt | 5 +++++ .../intranet-tmpl/prog/js/pages/preferences.js | 7 +++++++ svc/config/systempreferences | 14 ++++++++++++++ 6 files changed, 33 insertions(+), 2 deletions(-) diff --git a/admin/preferences.pl b/admin/preferences.pl index 20a187e3f1..05b98dbbe9 100755 --- a/admin/preferences.pl +++ b/admin/preferences.pl @@ -25,7 +25,7 @@ use C4::Context; use C4::Koha qw( getallthemes ); use C4::Languages qw( getTranslatedLanguages ); use C4::ClassSource qw( GetClassSources GetClassSource ); -use C4::Output qw( output_html_with_http_headers ); +use C4::Output qw( output_html_with_http_headers output_and_exit_if_error ); use C4::Templates; use Koha::Acquisition::Currencies; use Koha::Database::Columns; @@ -354,6 +354,7 @@ $tab ||= 'accounting'; # Ideally this should be "local-use" but preferences.pl my $highlighted; if ( $op eq 'save' ) { + output_and_exit_if_error($input, $cookie, $template, { check => 'csrf_token' }); foreach my $param ( $input->param() ) { my ( $pref ) = ( $param =~ /pref_(.*)/ ); diff --git a/admin/systempreferences.pl b/admin/systempreferences.pl index 1eb54552b1..d2d1369223 100755 --- a/admin/systempreferences.pl +++ b/admin/systempreferences.pl @@ -49,7 +49,7 @@ use C4::Context; use C4::Koha qw( getallthemes ); use C4::Languages qw( getTranslatedLanguages ); use C4::ClassSource qw( GetClassSources GetClassSource ); -use C4::Output qw( output_html_with_http_headers ); +use C4::Output qw( output_html_with_http_headers output_and_exit_if_error ); use YAML::XS; my %tabsysprefs; #we do no longer need to keep track of a tab per pref (yaml) @@ -235,6 +235,7 @@ if ($op) { } if ( $op eq 'update_and_reedit' ) { + output_and_exit_if_error($input, $cookie, $template, { check => 'csrf_token' }); foreach ( $input->param ) { } my $value = ''; @@ -302,6 +303,7 @@ if ( $op eq 'add_form' ) { ################## ADD_VALIDATE ################################## # called by add_form, used to insert/modify data in DB } elsif ( $op eq 'add_validate' ) { + output_and_exit_if_error($input, $cookie, $template, { check => 'csrf_token' }); # to handle multiple values my $value; @@ -348,6 +350,7 @@ if ( $op eq 'add_form' ) { ################## DELETE_CONFIRMED ################################## # called by delete_confirm, used to effectively confirm deletion of data in DB } elsif ( $op eq 'delete_confirmed' ) { + output_and_exit_if_error($input, $cookie, $template, { check => 'csrf_token' }); C4::Context->delete_preference($searchfield); # END $OP eq DELETE_CONFIRMED ################## DEFAULT ################################## diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt index b1bd23b314..3b8eb35bfe 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt @@ -58,6 +58,7 @@

[% TAB.tab_title | html %] preferences

+ [% INCLUDE 'csrf-token.inc' %] [% UNLESS ( searchfield ) %]
[% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/systempreferences.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/systempreferences.tt index cc1d9063a5..d010b36782 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/systempreferences.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/systempreferences.tt @@ -75,6 +75,8 @@ [% END #/ WRAPPER breadcrumbs %] [% END #/ WRAPPER sub-header.inc %] +[% INCLUDE 'blocking_errors.inc' %] +
@@ -94,6 +96,7 @@ [% ELSE %] [% END %] + [% INCLUDE 'csrf-token.inc' %]
System preference details
    @@ -279,6 +282,7 @@ + [% INCLUDE 'csrf-token.inc' %] @@ -333,6 +337,7 @@ [% ELSE %] [% END %] + [% INCLUDE 'csrf-token.inc' %] [% IF ( loo.type_free ) %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/pages/preferences.js b/koha-tmpl/intranet-tmpl/prog/js/pages/preferences.js index 92998b505a..535bc0ac5a 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/pages/preferences.js +++ b/koha-tmpl/intranet-tmpl/prog/js/pages/preferences.js @@ -25,6 +25,13 @@ KOHA.Preferences = { humanMsg.displayAlert( __("Nothing to save") ); return; } + let csrf_token_el = $( form ).find('input[name="csrf_token"]'); + if (csrf_token_el.length > 0){ + let csrf_token = csrf_token_el.val(); + if (csrf_token){ + data += '&' + 'csrf_token=' + csrf_token; + } + } KOHA.AJAX.MarkRunning($(form).find('.save-all'), __("Saving...") ); KOHA.AJAX.Submit( { data: data, diff --git a/svc/config/systempreferences b/svc/config/systempreferences index 367f220b44..fd09218b6b 100755 --- a/svc/config/systempreferences +++ b/svc/config/systempreferences @@ -23,6 +23,7 @@ use Modern::Perl; use C4::Context; use C4::Service; use C4::Log; +use Koha::Token; =head1 NAME @@ -63,6 +64,12 @@ Used to set a single system preference. sub set_preference { my ( $preference ) = @_; + die "wrong_csrf_token\n" unless Koha::Token->new->check_csrf( + { + session_id => scalar $query->cookie('CGISESSID'), + token => scalar $query->param('csrf_token'), + } + ); my $value = join( ',', $query->param( 'value' ) ); C4::Context->set_preference( $preference, $value ); @@ -122,6 +129,13 @@ pref_virtualshelves=0 =cut sub set_preferences { + die "wrong_csrf_token\n" unless Koha::Token->new->check_csrf( + { + session_id => scalar $query->cookie('CGISESSID'), + token => scalar $query->param('csrf_token'), + } + ); + foreach my $param ( $query->param() ) { my ( $pref ) = ( $param =~ /pref_(.*)/ );