Skip to content

Commit 0494a0c

Browse files
author
Florian Schaal
committed
2 parents a4cfc3c + 1e24e99 commit 0494a0c

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

interface/lib/classes/tform_base.inc.php

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,30 @@ function getHTML($record, $tab, $action = 'NEW') {
414414
if(!is_array($this->formDef)) $app->error("No form definition found.");
415415
if(!is_array($this->formDef['tabs'][$tab])) $app->error("The tab is empty or does not exist (TAB: $tab).");
416416

417+
/* CSRF PROTECTION */
418+
// generate csrf protection id and key
419+
$_csrf_id = uniqid($this->formDef['name'] . '_');
420+
$_csrf_value = sha1(uniqid(microtime(true), true));
421+
if(!isset($_SESSION['_csrf'])) $_SESSION['_csrf'] = array();
422+
if(!isset($_SESSION['_csrf_timeout'])) $_SESSION['_csrf_timeout'] = array();
423+
$_SESSION['_csrf'][$_csrf_id] = $_csrf_value;
424+
$_SESSION['_csrf_timeout'][$_csrf_id] = time() + 3600; // timeout hash in 1 hour
425+
$this->formDef['tabs'][$tab]['fields']['_csrf_id'] = array(
426+
'datatype' => 'VARCHAR',
427+
'formtype' => 'TEXT',
428+
'default' => $_csrf_id,
429+
'value' => $_csrf_id
430+
);
431+
$this->formDef['tabs'][$tab]['fields']['_csrf_key'] = array(
432+
'datatype' => 'VARCHAR',
433+
'formtype' => 'TEXT',
434+
'default' => $_csrf_value,
435+
'value' => $_csrf_value
436+
);
437+
$record['_csrf_id'] = $_csrf_id;
438+
$record['_csrf_key'] = $_csrf_value;
439+
/* CSRF PROTECTION */
440+
417441
$new_record = array();
418442
if($action == 'EDIT') {
419443
$record = $this->decode($record, $tab);
@@ -669,8 +693,50 @@ function getHTML($record, $tab, $action = 'NEW') {
669693
*/
670694
protected function _encode($record, $tab, $dbencode = true, $api = false) {
671695
global $app;
672-
if($api == true) $fields = &$this->formDef['fields'];
673-
else $fields = &$this->formDef['tabs'][$tab]['fields'];
696+
if($api == true) {
697+
$fields = &$this->formDef['fields'];
698+
} else {
699+
$fields = &$this->formDef['tabs'][$tab]['fields'];
700+
/* CSRF PROTECTION */
701+
if(isset($_POST) && is_array($_POST)) {
702+
$_csrf_valid = false;
703+
if(isset($_POST['_csrf_id']) && isset($_POST['_csrf_key'])) {
704+
$_csrf_id = trim($_POST['_csrf_id']);
705+
$_csrf_key = trim($_POST['_csrf_key']);
706+
if(isset($_SESSION['_csrf']) && isset($_SESSION['_csrf'][$_csrf_id]) && isset($_SESSION['_csrf_timeout']) && isset($_SESSION['_csrf_timeout'][$_csrf_id])) {
707+
if($_SESSION['_csrf'][$_csrf_id] === $_csrf_key && $_SESSION['_csrf_timeout'] >= time()) $_csrf_valid = true;
708+
}
709+
}
710+
if($_csrf_valid !== true) {
711+
$app->log('CSRF attempt blocked. Referer: ' . (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'unknown'), LOGLEVEL_WARN);
712+
$errmsg = 'err_csrf_attempt_blocked';
713+
$this->errorMessage .= ($api == true ? $errmsg : $this->wordbook[$errmsg]."<br />") . "\r\n";
714+
unset($_POST);
715+
unset($record);
716+
}
717+
$_SESSION['_csrf'][$_csrf_id] = null;
718+
$_SESSION['_csrf_timeout'][$_csrf_id] = null;
719+
unset($_SESSION['_csrf'][$_csrf_id]);
720+
unset($_SESSION['_csrf_timeout'][$_csrf_id]);
721+
722+
if(isset($_SESSION['_csrf_timeout']) && is_array($_SESSION['_csrf_timeout'])) {
723+
$to_unset = array();
724+
foreach($_SESSION['_csrf_timeout'] as $_csrf_id => $timeout) {
725+
if($timeout < time()) $to_unset[] = $_csrf_id;
726+
}
727+
foreach($to_unset as $_csrf_id) {
728+
$_SESSION['_csrf'][$_csrf_id] = null;
729+
$_SESSION['_csrf_timeout'][$_csrf_id] = null;
730+
unset($_SESSION['_csrf'][$_csrf_id]);
731+
unset($_SESSION['_csrf_timeout'][$_csrf_id]);
732+
}
733+
unset($to_unset);
734+
}
735+
}
736+
/* CSRF PROTECTION */
737+
}
738+
739+
$new_record = array();
674740
if(is_array($record)) {
675741
foreach($fields as $key => $field) {
676742

interface/lib/lang/de.lng

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ $wb['top_menu_mailuser'] = 'E-Mail Benutzer';
4141
$wb['top_menu_domain'] = 'Domains';
4242
$wb['top_menu_dashboard'] = 'Übersicht';
4343
$wb['latest_news_txt'] = 'Neuigkeiten';
44+
$wb['err_csrf_attempt_blocked'] = 'CSRF-Versuch blockiert.';
4445
$wb['top_menu_vm'] = 'vServer';
4546
$wb['daynamesmin_su'] = 'So';
4647
$wb['daynamesmin_mo'] = 'Mo';

interface/lib/lang/en.lng

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ $wb['datalog_status_d_web_folder'] = 'Delete folder protection';
131131
$wb['datalog_status_i_web_folder_user'] = 'Create folder protection user';
132132
$wb['datalog_status_u_web_folder_user'] = 'Update folder protection user';
133133
$wb['datalog_status_d_web_folder_user'] = 'Delete folder protection user';
134+
$wb['err_csrf_attempt_blocked'] = 'CSRF attempt blocked.';
134135
$wb['login_as_txt'] = 'Log in as';
135136
$wb["no_domain_perm"] = 'You have no permission for this domain.';
136137
$wb["no_destination_perm"] = 'You have no permission for this destination.';

interface/web/themes/default/templates/tabbed_form.tpl.htm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ <h1><tmpl_var name="form_hint"></h1>
3636
</div>
3737
</div>
3838

39+
<input type="hidden" name="_csrf_id" value="{tmpl_var name='_csrf_id'}" />
40+
<input type="hidden" name="_csrf_key" value="{tmpl_var name='_csrf_key'}" />
3941
<input type="hidden" name="next_tab" value="">
4042
<input type="hidden" name="phpsessid" value="{tmpl_var name='phpsessid'}">
4143
</div>
42-
43-

0 commit comments

Comments
 (0)