Add CSRF protections
This commit is contained in:
parent
f4efaadad1
commit
e5947db7f1
@ -16,6 +16,7 @@ body {
|
||||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
margin-bottom: 30px;
|
||||
max-width: 780px;
|
||||
color: #333;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
@ -375,7 +376,6 @@ nav .active a {
|
||||
font-size: 90%;
|
||||
display: inline;
|
||||
padding-right: 5px;
|
||||
border-right: 1px dotted #ccc;
|
||||
}
|
||||
|
||||
.page-header li:last-child {
|
||||
|
@ -14,13 +14,15 @@ Router\get_action('new-db', function() {
|
||||
|
||||
Response\html(Template\layout('new_db', array(
|
||||
'errors' => array(),
|
||||
'values' => array(),
|
||||
'values' => array(
|
||||
'csrf' => Model\Config\generate_csrf(),
|
||||
),
|
||||
'menu' => 'config',
|
||||
'title' => t('New database')
|
||||
)));
|
||||
}
|
||||
|
||||
Response\redirect('?action=config');
|
||||
Response\redirect('?action=about');
|
||||
});
|
||||
|
||||
// Create a new database
|
||||
@ -29,6 +31,7 @@ Router\post_action('new-db', function() {
|
||||
if (ENABLE_MULTIPLE_DB) {
|
||||
|
||||
$values = Request\values();
|
||||
Model\Config\check_csrf_values($values);
|
||||
list($valid, $errors) = Model\Database\validate($values);
|
||||
|
||||
if ($valid) {
|
||||
@ -40,18 +43,18 @@ Router\post_action('new-db', function() {
|
||||
Session\flash_error(t('Unable to create the new database.'));
|
||||
}
|
||||
|
||||
Response\redirect('?action=config');
|
||||
Response\redirect('?action=about');
|
||||
}
|
||||
|
||||
Response\html(Template\layout('new_db', array(
|
||||
'errors' => $errors,
|
||||
'values' => $values,
|
||||
'values' => $values + array('csrf' => Model\Config\generate_csrf()),
|
||||
'menu' => 'config',
|
||||
'title' => t('New database')
|
||||
)));
|
||||
}
|
||||
|
||||
Response\redirect('?action=config');
|
||||
Response\redirect('?action=about');
|
||||
});
|
||||
|
||||
// Auto-update
|
||||
@ -73,22 +76,30 @@ Router\get_action('auto-update', function() {
|
||||
// Re-generate tokens
|
||||
Router\get_action('generate-tokens', function() {
|
||||
|
||||
if (Model\Config\check_csrf(Request\param('csrf'))) {
|
||||
Model\Config\new_tokens();
|
||||
}
|
||||
|
||||
Response\redirect('?action=api');
|
||||
});
|
||||
|
||||
// Optimize the database manually
|
||||
Router\get_action('optimize-db', function() {
|
||||
|
||||
if (Model\Config\check_csrf(Request\param('csrf'))) {
|
||||
Database::get('db')->getConnection()->exec('VACUUM');
|
||||
Response\redirect('?action=config');
|
||||
}
|
||||
|
||||
Response\redirect('?action=about');
|
||||
});
|
||||
|
||||
// Download the compressed database
|
||||
Router\get_action('download-db', function() {
|
||||
|
||||
if (Model\Config\check_csrf(Request\param('csrf'))) {
|
||||
Response\force_download('db.sqlite.gz');
|
||||
Response\binary(gzencode(file_get_contents(\Model\Database\get_path())));
|
||||
Response\binary(gzencode(file_get_contents(Model\Database\get_path())));
|
||||
}
|
||||
});
|
||||
|
||||
// Display preferences page
|
||||
@ -96,8 +107,7 @@ Router\get_action('config', function() {
|
||||
|
||||
Response\html(Template\layout('config', array(
|
||||
'errors' => array(),
|
||||
'values' => Model\Config\get_all(),
|
||||
'db_size' => filesize(\Model\Database\get_path()),
|
||||
'values' => Model\Config\get_all() + array('csrf' => Model\Config\generate_csrf()),
|
||||
'languages' => Model\Config\get_languages(),
|
||||
'timezones' => Model\Config\get_timezones(),
|
||||
'autoflush_options' => Model\Config\get_autoflush_options(),
|
||||
@ -115,6 +125,7 @@ Router\get_action('config', function() {
|
||||
Router\post_action('config', function() {
|
||||
|
||||
$values = Request\values() + array('nocontent' => 0);
|
||||
Model\Config\check_csrf_values($values);
|
||||
list($valid, $errors) = Model\Config\validate_modification($values);
|
||||
|
||||
if ($valid) {
|
||||
@ -131,8 +142,7 @@ Router\post_action('config', function() {
|
||||
|
||||
Response\html(Template\layout('config', array(
|
||||
'errors' => $errors,
|
||||
'values' => Model\Config\get_all(),
|
||||
'db_size' => filesize(\Model\Database\get_path()),
|
||||
'values' => Model\Config\get_all() + array('csrf' => Model\Config\generate_csrf()),
|
||||
'languages' => Model\Config\get_languages(),
|
||||
'timezones' => Model\Config\get_timezones(),
|
||||
'autoflush_options' => Model\Config\get_autoflush_options(),
|
||||
@ -160,6 +170,7 @@ Router\get_action('help', function() {
|
||||
Router\get_action('about', function() {
|
||||
|
||||
Response\html(Template\layout('about', array(
|
||||
'csrf' => Model\Config\generate_csrf(),
|
||||
'config' => Model\Config\get_all(),
|
||||
'db_size' => filesize(\Model\Database\get_path()),
|
||||
'menu' => 'config',
|
||||
@ -171,6 +182,7 @@ Router\get_action('about', function() {
|
||||
Router\get_action('api', function() {
|
||||
|
||||
Response\html(Template\layout('api', array(
|
||||
'csrf' => Model\Config\generate_csrf(),
|
||||
'config' => Model\Config\get_all(),
|
||||
'menu' => 'config',
|
||||
'title' => t('API')
|
||||
|
@ -136,7 +136,9 @@ Router\get_action('feeds', function() {
|
||||
Router\get_action('add', function() {
|
||||
|
||||
Response\html(Template\layout('add', array(
|
||||
'values' => array(),
|
||||
'values' => array(
|
||||
'csrf' => Model\Config\generate_csrf(),
|
||||
),
|
||||
'errors' => array(),
|
||||
'menu' => 'feeds',
|
||||
'title' => t('New subscription')
|
||||
@ -148,6 +150,7 @@ Router\action('subscribe', function() {
|
||||
|
||||
if (Request\is_post()) {
|
||||
$values = Request\values();
|
||||
Model\Config\check_csrf_values($values);
|
||||
$url = isset($values['url']) ? $values['url'] : '';
|
||||
}
|
||||
else {
|
||||
@ -173,7 +176,10 @@ Router\action('subscribe', function() {
|
||||
}
|
||||
|
||||
Response\html(Template\layout('add', array(
|
||||
'values' => array('url' => $url),
|
||||
'values' => array(
|
||||
'url' => $url,
|
||||
'csrf' => Model\Config\generate_csrf(),
|
||||
),
|
||||
'menu' => 'feeds',
|
||||
'title' => t('Subscriptions')
|
||||
)));
|
||||
|
@ -23,7 +23,9 @@ Router\get_action('login', function() {
|
||||
|
||||
Response\html(Template\load('login', array(
|
||||
'errors' => array(),
|
||||
'values' => array(),
|
||||
'values' => array(
|
||||
'csrf' => Model\Config\generate_csrf(),
|
||||
),
|
||||
'databases' => Model\Database\get_list(),
|
||||
'current_database' => Model\Database\select()
|
||||
)));
|
||||
@ -33,6 +35,7 @@ Router\get_action('login', function() {
|
||||
Router\post_action('login', function() {
|
||||
|
||||
$values = Request\values();
|
||||
Model\Config\check_csrf_values($values);
|
||||
list($valid, $errors) = Model\User\validate_login($values);
|
||||
|
||||
if ($valid) {
|
||||
@ -41,7 +44,7 @@ Router\post_action('login', function() {
|
||||
|
||||
Response\html(Template\load('login', array(
|
||||
'errors' => $errors,
|
||||
'values' => $values,
|
||||
'values' => $values + array('csrf' => Model\Config\generate_csrf()),
|
||||
'databases' => Model\Database\get_list(),
|
||||
'current_database' => Model\Database\select()
|
||||
)));
|
||||
|
@ -156,6 +156,43 @@ function get_nothing_to_read_redirections()
|
||||
);
|
||||
}
|
||||
|
||||
// Create a CSRF token
|
||||
function generate_csrf()
|
||||
{
|
||||
if (empty($_SESSION['csrf'])) {
|
||||
$_SESSION['csrf'] = array();
|
||||
}
|
||||
|
||||
$token = generate_token();
|
||||
$_SESSION['csrf'][$token] = true;
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
// Check CSRF token (form values)
|
||||
function check_csrf_values(array &$values)
|
||||
{
|
||||
if (empty($values['csrf']) || ! isset($_SESSION['csrf'][$values['csrf']])) {
|
||||
$values = array();
|
||||
}
|
||||
else {
|
||||
|
||||
unset($_SESSION['csrf'][$values['csrf']]);
|
||||
unset($values['csrf']);
|
||||
}
|
||||
}
|
||||
|
||||
// Check CSRF token
|
||||
function check_csrf($token)
|
||||
{
|
||||
if (isset($_SESSION['csrf'][$token])) {
|
||||
unset($_SESSION['csrf'][$values['csrf']]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate a token from /dev/urandom or with uniqid() if open_basedir is enabled
|
||||
function generate_token()
|
||||
{
|
||||
|
@ -22,8 +22,8 @@
|
||||
<h3><?= t('Database') ?></h3>
|
||||
<ul>
|
||||
<li><?= t('Database size:') ?> <strong><?= Helper\format_bytes($db_size) ?></strong></li>
|
||||
<li><a href="?action=optimize-db"><?= t('Optimize the database') ?></a> <?= t('(VACUUM command)') ?></li>
|
||||
<li><a href="?action=download-db"><?= t('Download the entire database') ?></a> <?= t('(Gzip compressed Sqlite file)') ?></li>
|
||||
<li><a href="?action=optimize-db&csrf=<?= $csrf ?>"><?= t('Optimize the database') ?></a> <?= t('(VACUUM command)') ?></li>
|
||||
<li><a href="?action=download-db&csrf=<?= $csrf ?>"><?= t('Download the entire database') ?></a> <?= t('(Gzip compressed Sqlite file)') ?></li>
|
||||
<?php if (ENABLE_MULTIPLE_DB): ?>
|
||||
<li>
|
||||
<a href="?action=new-db"><?= t('Add a new database (new user)') ?></a>
|
||||
|
@ -8,6 +8,9 @@
|
||||
</div>
|
||||
|
||||
<form method="post" action="?action=subscribe" autocomplete="off">
|
||||
|
||||
<?= Helper\form_hidden('csrf', $values) ?>
|
||||
|
||||
<?= Helper\form_label(t('Website or Feed URL'), 'url') ?>
|
||||
<?= Helper\form_text('url', $values, array(), array('required', 'autofocus', 'placeholder="'.t('http://website/').'"')) ?><br/><br/>
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
<li><?= t('API endpoint:') ?> <strong><?= Helper\get_current_base_url().'jsonrpc.php' ?></strong></li>
|
||||
<li><?= t('API username:') ?> <strong><?= Helper\escape($config['username']) ?></strong></li>
|
||||
<li><?= t('API token:') ?> <strong><?= Helper\escape($config['api_token']) ?></strong></li>
|
||||
<li><a href="?action=generate-tokens"><?= t('Generate new tokens') ?></a></li>
|
||||
<li><a href="?action=generate-tokens&csrf=<?= $csrf ?>"><?= t('Generate new tokens') ?></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -9,6 +9,8 @@
|
||||
<section>
|
||||
<form method="post" action="?action=config" autocomplete="off">
|
||||
|
||||
<?= Helper\form_hidden('csrf', $values) ?>
|
||||
|
||||
<?= Helper\form_label(t('Username'), 'username') ?>
|
||||
<?= Helper\form_text('username', $values, $errors, array('required')) ?><br/>
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
<form method="post" action="?action=login" id="login-form">
|
||||
|
||||
<?= Helper\form_hidden('csrf', $values) ?>
|
||||
|
||||
<?= Helper\form_label(t('Username'), 'username') ?>
|
||||
<?= Helper\form_text('username', $values, $errors, array('autofocus', 'required')) ?><br/>
|
||||
|
||||
|
@ -2,10 +2,16 @@
|
||||
<h2><?= t('New database') ?></h2>
|
||||
<ul>
|
||||
<li><a href="?action=config"><?= t('preferences') ?></a></li>
|
||||
<li><a href="?action=about"><?= t('about') ?></a></li>
|
||||
<li><a href="?action=help"><?= t('help') ?></a></li>
|
||||
<li><a href="?action=api"><?= t('api') ?></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form method="post" action="?action=new-db" autocomplete="off">
|
||||
|
||||
<?= Helper\form_hidden('csrf', $values) ?>
|
||||
|
||||
<?= Helper\form_label(t('Database name'), 'name') ?>
|
||||
<?= Helper\form_text('name', $values, $errors, array('required', 'autofocus')) ?>
|
||||
<p class="form-help"><?= t('The name must have only alpha-numeric characters') ?></p>
|
||||
|
Loading…
Reference in New Issue
Block a user