Use CSRF tokens on admin page

This commit is contained in:
Olivier PEREZ 2015-01-10 16:35:21 +01:00
parent e7ebd55299
commit 1df48988a6
4 changed files with 63 additions and 13 deletions

View File

@ -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();
$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();
$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');

View File

@ -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;
} }
} }

View File

@ -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['token'][$tokan_name]->getValue(); 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 $checked;
} }
} }

View File

@ -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>