Skip to content
Snippets Groups Projects
Commit 1df48988 authored by Olivier PEREZ's avatar Olivier PEREZ
Browse files

Use CSRF tokens on admin page

parent e7ebd552
No related branches found
No related tags found
No related merge requests found
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
use Framadate\Services\AdminPollService; use Framadate\Services\AdminPollService;
use Framadate\Services\LogService; use Framadate\Services\LogService;
use Framadate\Services\PollService; use Framadate\Services\PollService;
use Framadate\Services\SecurityService;
use Framadate\Services\SuperAdminService; use Framadate\Services\SuperAdminService;
use Framadate\Utils; use Framadate\Utils;
...@@ -39,18 +40,19 @@ $logService = new LogService(); ...@@ -39,18 +40,19 @@ $logService = new LogService();
$pollService = new PollService($connect, $logService); $pollService = new PollService($connect, $logService);
$adminPollService = new AdminPollService($connect, $pollService, $logService); $adminPollService = new AdminPollService($connect, $pollService, $logService);
$superAdminService = new SuperAdminService($connect); $superAdminService = new SuperAdminService($connect);
$securityService = new SecurityService();
/* PAGE */ /* PAGE */
/* ---- */ /* ---- */
if (!empty($_POST['delete_poll'])) { if (!empty($_POST['delete_poll']) && $securityService->checkCsrf('admin', $_POST['csrf'])) {
$delete_id = filter_input(INPUT_POST, 'delete_poll', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-z0-9]+$/']]); $delete_id = filter_input(INPUT_POST, 'delete_poll', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]);
$poll_to_delete = $pollService->findById($delete_id); $poll_to_delete = $pollService->findById($delete_id);
} }
// Traitement de la confirmation de suppression // Traitement de la confirmation de suppression
if (!empty($_POST['delete_confirm'])) { if (!empty($_POST['delete_confirm']) && $securityService->checkCsrf('admin', $_POST['csrf'])) {
$poll_id = filter_input(INPUT_POST, 'delete_confirm', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-z0-9]+$/']]); $poll_id = filter_input(INPUT_POST, 'delete_confirm', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]);
$adminPollService->deleteEntirePoll($poll_id); $adminPollService->deleteEntirePoll($poll_id);
} }
...@@ -60,5 +62,6 @@ $polls = $superAdminService->findAllPolls(); ...@@ -60,5 +62,6 @@ $polls = $superAdminService->findAllPolls();
$smarty->assign('polls', $polls); $smarty->assign('polls', $polls);
$smarty->assign('poll_to_delete', $poll_to_delete); $smarty->assign('poll_to_delete', $poll_to_delete);
$smarty->assign('log_file', is_readable('../' . LOG_FILE) ? LOG_FILE : null); $smarty->assign('log_file', is_readable('../' . LOG_FILE) ? LOG_FILE : null);
$smarty->assign('crsf', $securityService->getToken('admin'));
$smarty->display('admin/polls.tpl'); $smarty->display('admin/polls.tpl');
...@@ -3,18 +3,32 @@ namespace Framadate\Security; ...@@ -3,18 +3,32 @@ namespace Framadate\Security;
class Token { class Token {
private $tokan_name;
private $time; private $time;
private $value; private $value;
function __construct($tokan_name, $time) { function __construct() {
$this->tokan_name = $tokan_name; $this->time = time() + TOKEN_TIME;
$this->time = $time; $this->value = $this->generate();
$this->value = $this->generate();
} }
private function generate() { private function generate() {
// TODO return sha1(uniqid(mt_rand(), true));
}
public function getTime() {
return $this->time;
}
public function getValue() {
return $this->value;
}
public function isGone() {
return $this->time < time();
}
public function check($value) {
return $value === $this->value;
} }
} }
...@@ -8,12 +8,44 @@ class SecurityService { ...@@ -8,12 +8,44 @@ class SecurityService {
function __construct() { function __construct() {
} }
/**
* Get a CSRF token by name, or (re)create it.
*
* It creates a new token if :
* <ul>
* <li>There no token with the given name in session</li>
* <li>The token time is in past</li>
* </ul>
*
* @param $tokan_name string The name of the CSRF token
* @return Token The token
*/
function getToken($tokan_name) { function getToken($tokan_name) {
if (!isset($_SESSION['token']) || !isset($_SESSION['token'][$tokan_name])) { if (!isset($_SESSION['tokens'])) {
$_SESSION['token'][$tokan_name] = new Token($tokan_name, 60*5); $_SESSION['tokens'] = [];
}
if (!isset($_SESSION['tokens'][$tokan_name]) || $_SESSION['tokens'][$tokan_name]->isGone()) {
$_SESSION['tokens'][$tokan_name] = new Token();
}
return $_SESSION['tokens'][$tokan_name]->getValue();
}
/**
* Check if a given value is corresponding to the token in session.
*
* @param $tokan_name string Name of the token
* @param $csrf string Value to check
* @return bool true if the token is well checked
*/
public function checkCsrf($tokan_name, $csrf) {
$checked = $_SESSION['tokens'][$tokan_name]->getValue() === $csrf;
if($checked) {
unset($_SESSION['tokens'][$tokan_name]);
} }
return $_SESSION['token'][$tokan_name]->getValue(); return $checked;
} }
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
{block 'admin_main'} {block 'admin_main'}
<form action="" method="POST"> <form action="" method="POST">
<input type="hidden" name="csrf" value="{$crsf}"/>
{if $poll_to_delete} {if $poll_to_delete}
<div class="alert alert-warning text-center"> <div class="alert alert-warning text-center">
<h3>{_("Confirm removal of the poll ")}"{$poll_to_delete->id}"</h3> <h3>{_("Confirm removal of the poll ")}"{$poll_to_delete->id}"</h3>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment