From fcec264f9ce5bc356e003ee2a5271faf23a765b9 Mon Sep 17 00:00:00 2001
From: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Date: Tue, 7 Feb 2017 09:09:33 +0100
Subject: [PATCH] Bug 18019: Add CSRF protection to authorities-home.pl
 (op==delete)
Content-Type: text/plain; charset=utf-8

Without this patch, it is possible to delete authority records with URL
manipulation.
Like: /cgi-bin/koha/authorities/authorities-home.pl?op=delete&authid=[XXX]

Test plan:
[1] Go to Authorities. Search for some authorities (without links).
[2] Delete an authority. Should work.
[3] Construct an URL like above to delete another authority. Should fail.
    Under Plack this results in an internal server error, the log tells
    you: Wrong CSRF token.

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
---
 authorities/authorities-home.pl                         | 17 +++++++++++++++++
 .../prog/en/includes/authorities-search.inc             |  4 ++++
 .../prog/en/modules/authorities/searchresultlist.tt     |  3 ++-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/authorities/authorities-home.pl b/authorities/authorities-home.pl
index 6e0a8fe..06aebb2 100755
--- a/authorities/authorities-home.pl
+++ b/authorities/authorities-home.pl
@@ -21,6 +21,8 @@ use strict;
 use warnings;
 
 use CGI qw ( -utf8 );
+use Digest::MD5 qw(md5_base64);
+use Encode qw( encode );
 use URI::Escape;
 use C4::Auth;
 
@@ -36,6 +38,7 @@ use C4::Search::History;
 use Koha::Authority::Types;
 use Koha::SearchEngine::Search;
 use Koha::SearchEngine::QueryBuilder;
+use Koha::Token;
 
 my $query = new CGI;
 my $dbh   = C4::Context->dbh;
@@ -58,6 +61,13 @@ if ( $op eq "delete" ) {
             debug           => 1,
         }
     );
+
+    die "Wrong CSRF token" unless Koha::Token->new->check_csrf({
+        id     => Encode::encode( 'UTF-8', $loggedinuser ),
+        secret => md5_base64( Encode::encode( 'UTF-8', C4::Context->config('pass') ) ),
+        token  => scalar $query->param('csrf_token'),
+    });
+
     &DelAuthority( $authid, 1 );
 
     if ( $query->param('operator') ) {
@@ -111,6 +121,13 @@ if ( $op eq "do_search" ) {
         }
     );
 
+    $template->param(
+        csrf_token => Koha::Token->new->generate_csrf({
+            id => Encode::encode( 'UTF-8', $loggedinuser ),
+            secret => md5_base64( Encode::encode( 'UTF-8', C4::Context->config('pass') ) ),
+        }),
+    );
+
     # search history
     if (C4::Context->preference('EnableSearchHistory')) {
         if ( $startfrom == 1) {
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/authorities-search.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/authorities-search.inc
index 45517c8..3c1e26e 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/authorities-search.inc
+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/authorities-search.inc
@@ -21,6 +21,7 @@
     <div id="mainmain_heading" class="residentsearch">
     <p class="tip">Enter main heading ($a only):</p>
     <form action="/cgi-bin/koha/authorities/authorities-home.pl" method="get">
+        <input type="hidden" name="csrf_token" value="[% csrf_token %]" />
         <input type="hidden" name="op" value="do_search" />
         <input type="hidden" name="type" value="intranet" />
         <select name="authtypecode">
@@ -77,6 +78,7 @@
     <div id="main_heading" class="residentsearch">
     <p class="tip">Enter main heading:</p>
     <form action="/cgi-bin/koha/authorities/authorities-home.pl" method="get">
+        <input type="hidden" name="csrf_token" value="[% csrf_token %]" />
         <input type="hidden" name="op" value="do_search" />
         <input type="hidden" name="type" value="intranet" />
         <select name="authtypecode">
@@ -133,6 +135,7 @@
     <div id="matchheading_search" class="residentsearch">
     <p class="tip">Enter any heading:</p>
     <form action="/cgi-bin/koha/authorities/authorities-home.pl" method="get">
+        <input type="hidden" name="csrf_token" value="[% csrf_token %]" />
         <input type="hidden" name="op" value="do_search" />
         <input type="hidden" name="type" value="intranet" />
         <select name="authtypecode">
@@ -187,6 +190,7 @@
     <div id="entire_record" class="residentsearch">
     <p class="tip">Enter any authority field:</p>
     <form action="/cgi-bin/koha/authorities/authorities-home.pl" method="get">
+        <input type="hidden" name="csrf_token" value="[% csrf_token %]" />
         <input type="hidden" name="op" value="do_search" />
         <input type="hidden" name="type" value="intranet" />
         <select name="authtypecode">
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/authorities/searchresultlist.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/authorities/searchresultlist.tt
index 563c44e..76e4589 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/authorities/searchresultlist.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/authorities/searchresultlist.tt
@@ -19,7 +19,8 @@ function confirm_deletion(id) {
           + "&orderby=[% orderby %]"
           + "&value=[% value |url %]"
           + "&startfrom=[% startfrom %]"
-          + "&resultsperpage=[% resultsperpage %]";
+          + "&resultsperpage=[% resultsperpage %]"
+          + "&csrf_token=[% csrf_token %]";
     }
 }
 
-- 
2.1.4