diff --git a/scp/apikeys.php b/scp/apikeys.php index 1f84789a96..10c288d643 100644 --- a/scp/apikeys.php +++ b/scp/apikeys.php @@ -16,11 +16,21 @@ require('admin.inc.php'); include_once(INCLUDE_DIR.'class.api.php'); +if ($_SERVER['REQUEST_METHOD'] === 'GET') { + if (!isset($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } +} + $api=null; if($_REQUEST['id'] && !($api=API::lookup($_REQUEST['id']))) $errors['err']=sprintf(__('%s: Unknown or invalid ID.'), __('API Key')); if($_POST){ + if (!isset($_POST['csrf_token'], $_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { + http_response_code(400); + exit('Invalid CSRF token'); + } switch(strtolower($_POST['do'])){ case 'update': if(!$api){ diff --git a/scp/canned.php b/scp/canned.php index 409aa28bac..d450259acb 100644 --- a/scp/canned.php +++ b/scp/canned.php @@ -45,6 +45,13 @@ )), )); +// Generate CSRF token +if (!isset($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); +} +// Add CSRF token to the form as a hidden field +$canned_form->addHiddenField('csrf_token', $_SESSION['csrf_token']); + // Set fields' attachments so exsting files stay put if ($canned && $canned->attachments @@ -53,6 +60,13 @@ } if ($_POST) { + // CSRF validation + $csrf = $_POST['csrf_token'] ?? ''; + if (!$csrf || !hash_equals($_SESSION['csrf_token'], $csrf)) { + header('HTTP/1.1 403 Forbidden'); + exit('Invalid CSRF token'); + } + switch(strtolower($_POST['do'])) { case 'update': if(!$canned) { diff --git a/scp/dashboard.php b/scp/dashboard.php index 052d549b10..24964bc7de 100644 --- a/scp/dashboard.php +++ b/scp/dashboard.php @@ -15,9 +15,21 @@ **********************************************************************/ require('staff.inc.php'); +// CSRF token generation +if (empty($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); +} + require_once INCLUDE_DIR . 'class.report.php'; if ($_POST['export']) { + // CSRF token validation + if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { + header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); + echo 'Invalid CSRF token'; + exit; + } + $report = new OverviewReport($_POST['start'], $_POST['period']); switch (true) { case ($data = $report->getTabularData($_POST['export'])): diff --git a/scp/departments.php b/scp/departments.php index 63aa70582c..e908bdc9f2 100644 --- a/scp/departments.php +++ b/scp/departments.php @@ -20,6 +20,13 @@ $errors['err']=sprintf(__('%s: Unknown or invalid ID.'), __('department')); if($_POST){ + // CSRF token validation + if (!isset($_POST['csrf_token'], $_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { + header('HTTP/1.1 403 Forbidden'); + echo 'Invalid CSRF token'; + exit; + } + switch(strtolower($_POST['do'])){ case 'update': if(!$dept){ @@ -63,7 +70,7 @@ $msg=sprintf(__('Successfully made %s PUBLIC'), _N('selected department', 'selected departments', $count)); else - $warn=sprintf(__( + $warn=sprintf__( /* Phrase will read: of made PUBLIC */ '%1$d of %2$d %3$s made PUBLIC'), $num, $count, @@ -82,7 +89,7 @@ $msg = sprintf(__('Successfully made %s PRIVATE'), _N('selected department', 'selected epartments', $count)); else - $warn = sprintf(__( + $warn = sprintf__( /* Phrase will read: of made PRIVATE */ '%1$d of %2$d %3$s made PRIVATE'), $num, $count,