Skip to content

Commit

Permalink
Security fixes: XSS and CSRF
Browse files Browse the repository at this point in the history
  • Loading branch information
craigk5n committed Oct 14, 2021
1 parent a9720b9 commit d9729b4
Show file tree
Hide file tree
Showing 31 changed files with 241 additions and 61 deletions.
15 changes: 10 additions & 5 deletions access.php
Expand Up @@ -175,8 +175,9 @@
<h2>' . translate( 'User Access Control' )
. ( empty( $user_fullname ) ? '' : ': ' . $user_fullname ) . '</h2>
' . display_admin_link( false ) . '
<form action="access.php" method="post" name="SelectUser">
<select name="guser" onchange="document.SelectUser.submit()">'
<form action="access.php" method="post" name="SelectUser">';
print_form_key();
echo '<select name="guser" onchange="document.SelectUser.submit()">'
// Add a DEFAULT CONFIGURATION to be used as a mask.
. '
<option value="__default__"'
Expand Down Expand Up @@ -213,8 +214,9 @@
// defined in access.php.
assert( count( $order ) == ACCESS_NUMBER_FUNCTIONS );

echo '<form action="access.php" method="post" id="accessform" name="accessform">';
print_form_key();
echo '
<form action="access.php" method="post" id="accessform" name="accessform">
<input type="hidden" name="auser" value="' . $guser . '" />
<input type="hidden" name="guser" value="' . $guser . '" />
<table>
Expand Down Expand Up @@ -282,7 +284,9 @@
$userlist = get_list_of_users( $guser );
echo '
<h2 style="margin-bottom: 2px;">' . $pagetitle . '</h2>
<form action="access.php" method="post" name="SelectOther">
<form action="access.php" method="post" name="SelectOther">';
print_form_key();
echo '
<input type="hidden" name="guser" value="' . $guser . '" />
<select name="otheruser" onchange="document.SelectOther.submit()">'
// Add a DEFAULT CONFIGURATION to be used as a mask.
Expand All @@ -306,8 +310,9 @@
if( ! empty( $otheruser ) ) {
if( $allow_view_other ) {
$typeStr = translate( 'Type' );
echo '<form action="access.php" method="post" name="EditOther">';
print_form_key();
echo '
<form action="access.php" method="post" name="EditOther">
<input type="hidden" name="guser" value="' . $guser . '" />
<input type="hidden" name="otheruser" value="' . $otheruser . '" /><br />
<table cellpadding="5">
Expand Down
7 changes: 5 additions & 2 deletions admin.php
Expand Up @@ -23,9 +23,12 @@ function save_pref ( $prefs, $src ) {

// Validate key name. Should start with "admin_" and not include
// any unusual characters that might be an SQL injection attack.
if ( ! preg_match ( '/admin_[A-Za-z0-9_]+$/', $key ) )
if ( $key == 'csrf_form_key' ) {
// Ignore this for validation...
} else if ( ! preg_match ( '/admin_[A-Za-z0-9_]+$/', $key ) ) {
die_miserable_death ( str_replace ( 'XXX', $key,
translate ( 'Invalid setting name XXX.' ) ) );
}
} else {
$prefix = 'admin_';
$setting = $key;
Expand Down Expand Up @@ -238,7 +241,7 @@ function save_pref ( $prefs, $src ) {
. '\'dependent,menubar,scrollbars,height=400,width=400,innerHeight=420,'
. 'outerWidth=420\' );" /></h2>
<form action="admin.php" method="post" onsubmit="return valid_form( this );"'
. ' name="prefform">'
. ' name="prefform">' . csrf_form_key()
. display_admin_link() . '
<input class="btn btn-primary" type="submit" value="' . $saveStr
. '" name="" /><br /><br />
Expand Down
5 changes: 3 additions & 2 deletions approve_entry.php
Expand Up @@ -19,8 +19,9 @@
print_header();
echo '
<form action="approve_entry.php' . $q_string
. '" method="post" name="add_comments">
<table cellspacing="5">
. '" method="post" name="add_comments">';
print_form_key();
echo '<table cellspacing="5">
<tr>
<td class="aligncenter alignbottom"><h3>'
. translate ( 'Additional Comments (optional)' ) . '</h3></td>
Expand Down
2 changes: 1 addition & 1 deletion assistant_edit.php
Expand Up @@ -14,7 +14,7 @@
'<script type="text/javascript" src="includes/js/assistant_edit.js"></script>' );
echo '
<form action="assistant_edit_handler.php" method="post" '
. 'name="assistanteditform">' . ( $user ? '
. 'name="assistanteditform">' . csrf_form_key() . ( $user ? '
<input type="hidden" name="user" value="' . $user . '" />' : '' ) . '
<h2>';

Expand Down
2 changes: 1 addition & 1 deletion availability.php
Expand Up @@ -74,7 +74,7 @@
</div>
</div><br />
<form action="availability.php" method="post">
' . daily_matrix ( $date, $users ) . '
' . csrf_form_key() . daily_matrix ( $date, $users ) . '
</form>
' . print_trailer ( false, true, true );

Expand Down
2 changes: 1 addition & 1 deletion category.php
Expand Up @@ -66,7 +66,7 @@
if ( ( ( $add == '1' ) || ( ! empty ( $id ) ) ) && empty ( $error ) ) {
echo '
<form action="category_handler.php" method="post" name="catform" '
. 'enctype="multipart/form-data">' . $idStr . '
. 'enctype="multipart/form-data">' . csrf_form_key() . $idStr . '
<div class="form-inline">
<label class="col-sm-3 col-form-label" for="catname">' . translate ('Category Name') . '</label>
<input class="form-control" type="text" name="catname" size="20" value="'
Expand Down
2 changes: 1 addition & 1 deletion catsel.php
Expand Up @@ -33,7 +33,7 @@
<th colspan="3">' . translate ( 'Categories' ) . '</th>
</tr>
<form action="" method="post" name="editCategories" '
. 'onSubmit="sendCats( this )">
. 'onSubmit="sendCats( this )">' . csrf_form_key() . '
<tr>
<td class="aligntop">';

Expand Down
2 changes: 2 additions & 0 deletions docadd.php
Expand Up @@ -202,6 +202,7 @@
// Comment
?>
<form action="docadd.php" method="post" name="docform">
<?php print_form_key(); ?>
<input type="hidden" name="id" value="<?php echo $id?>" />
<input type="hidden" name="type" value="C" />

Expand All @@ -223,6 +224,7 @@
// Attachment
?>
<form action="docadd.php" method="post" name="docform" enctype="multipart/form-data">
<?php print_form_key(); ?>
<input type="hidden" name="id" value="<?php echo $id?>" />
<input type="hidden" name="type" value="A" />
<table>
Expand Down
5 changes: 3 additions & 2 deletions edit_entry.php
Expand Up @@ -101,7 +101,7 @@ function time_selection($prefix, $time = '', $trigger = false)
$checked = ' checked="checked"';
$selected = ' selected="selected"';

$eType = getGetValue('eType');
$eType = getGetValue('eType','event',true);
$id = getGetValue('id');

$copy = getValue('copy', '[01]');
Expand Down Expand Up @@ -567,6 +567,7 @@ function time_selection($prefix, $time = '', $trigger = false)

?>
<form action="edit_entry_handler.php" method="post" name="editentryform" id="editentryform">
<?php print_form_key(); ?>
<input type="hidden" name="eType" value="<?php echo $eType; ?>" />
<?php if (!empty($id) && (empty($copy) || $copy != '1')) { ?>
<input type="hidden" name="cal_id" value="<?php echo $id; ?>" />
Expand Down Expand Up @@ -1593,7 +1594,7 @@ function time_selection($prefix, $time = '', $trigger = false)
<div class="col-auto">
<input type="button" class="form-check btn btn-primary" value="<?php echo $saveStr; ?>" onclick="validate_and_submit()">
<?php if ($id > 0 && ($login == $create_by || $single_user == 'Y' || $is_admin)) { ?>
<a class="btn btn-danger" href="del_entry.php?id=' <?php echo $id; ?>" onclick="return confirm('<?php etranslate('Are you sure you want to delete this entry?'); ?>');">
<a class="btn btn-danger" href="del_entry.php?id=<?php echo $id; ?>&csrf_form_key=<?php echo getFormKey();?>" onclick="return confirm('<?php etranslate('Are you sure you want to delete this entry?'); ?>');">
<?php etranslate('Delete entry'); ?></a><br />
<?php } ?>
</div>
Expand Down
1 change: 1 addition & 0 deletions edit_entry_handler.php
Expand Up @@ -1272,6 +1272,7 @@ function sort_byday( $a, $b ) {
</ul>
' // User can confirm conflicts.
. '<form name="confirm" method="post">';
print_form_key();
foreach ($_POST as $xkey => $xval) {
if (is_array($xval)) {
$xkey .= "[]";
Expand Down
2 changes: 2 additions & 0 deletions edit_remotes.php
Expand Up @@ -79,10 +79,12 @@
$urlValue = ( empty ( $remotestemp_url )
? '' : htmlspecialchars ( $remotestemp_url ) );

$formKey = csrf_form_key();
echo <<<EOT
<h2>{$lableStr}</h2>
<form action="edit_remotes_handler.php" method="post" name="prefform"
onsubmit="return valid_form( this );">
${formKey}
<table cellpadding="2">
<tr>
<td><label for="calid">{$calIdStr}:</label></td>
Expand Down
1 change: 1 addition & 0 deletions edit_report.php
Expand Up @@ -207,6 +207,7 @@ function print_options ( $textarea, $option ) {
. ( $adding_report ? translate ( 'Add Report' ) : translate ( 'Edit Report' ) )
. '</h2>
<form action="edit_report_handler.php" method="post" name="reportform">'
. csrf_form_key()
. ( $updating_public ? '
<input type="hidden" name="public" value="1" />' : '' )
. ( ! $adding_report ? '
Expand Down
3 changes: 2 additions & 1 deletion edit_template.php
Expand Up @@ -124,7 +124,8 @@
}

echo '</h2>' . ( ! empty ( $error ) ? print_error ( $error ) : '
<form action="edit_template.php" method="post" name="reportform">
<form action="edit_template.php" method="post" name="reportform">'
. csrf_form_key() . '
<input type="hidden" name="type" value="' . $type . '" />'
. ( ! empty ( $ALLOW_USER_HEADER ) && $ALLOW_USER_HEADER == 'Y' && !
empty ( $user ) && $user != '__system__' ? '
Expand Down
1 change: 1 addition & 0 deletions export.php
Expand Up @@ -24,6 +24,7 @@
print_header ( array ( 'js/export_import.php', 'js/visible.php' ) );
echo '<h2>' . translate ( 'Export' ) . '</h2>
<form action="export_handler.php" method="post" name="exportform" id="exportform">
' . print_form_key() . '
<table class="table">
<tr>
<td><label for="exformat">' . translate ( 'Export format' )
Expand Down
11 changes: 7 additions & 4 deletions groups.php
Expand Up @@ -172,7 +172,8 @@ function load_groups() {
groups = [];
$('#group-tbody').html('<tr><td colspan="5"><?php echo $LOADING; ?></td></tr>');
$.post('users_ajax.php', {
action: 'group-list'
action: 'group-list',
csrf_form_key: '<?php echo getFormKey(); ?>'
},
function(data, status) {
var stringified = JSON.stringify(data);
Expand Down Expand Up @@ -295,7 +296,8 @@ function save_handler() {
action: "save-group",
id: id,
name: name,
users: users
users: users,
csrf_form_key: '<?php echo getFormKey(); ?>'
},
function(data, status) {
console.log('Data: ' + data);
Expand Down Expand Up @@ -357,7 +359,8 @@ function delete_handler() {

$.post('users_ajax.php', {
action: "delete-group",
id: id
id: id,
csrf_form_key: '<?php echo getFormKey(); ?>'
},
function(data, status) {
console.log('Data: ' + data);
Expand Down Expand Up @@ -395,4 +398,4 @@ function(data, status) {
}
</script>

<?php echo print_trailer(); ?>
<?php echo print_trailer(); ?>
3 changes: 2 additions & 1 deletion import.php
Expand Up @@ -123,7 +123,8 @@ function print_categories() {
$yesStr = translate ( 'Yes' );
echo '
<form action="import_handler.php" method="post" name="importform" '
. 'enctype="multipart/form-data" onsubmit="return checkExtension()">
. 'enctype="multipart/form-data" onsubmit="return checkExtension()">'
. print_form_key() . '
<table class="table">
<tr>
<td><label for="importtype">' . translate ( 'Import format' ) . ':</label></td>
Expand Down
72 changes: 66 additions & 6 deletions includes/formvars.php
Expand Up @@ -22,12 +22,41 @@ function preventHacking_helper($matches) {
return chr(hexdec($matches[1]));
}
function preventHacking ( $name, $instr ) {
global $PHP_SELF;
$script = basename($PHP_SELF);

$bannedTags = [
'APPLET', 'BODY', 'EMBED', 'FORM', 'HEAD',
'HTML', 'IFRAME', 'LINK', 'META', 'NOEMBED',
'NOFRAMES', 'NOSCRIPT', 'OBJECT', 'SCRIPT'];
$failed = false;

// If this is a POST, require a form key to prevent CSRF
// Assume all database db changes make use of POST or else
// they end in "_handler.php" or are one of a handful of known URLs.
if ($script == "login.php" || $script=="register.php" ||
$script == "search_handler.php") {
// No form token needed
} else if ($_SERVER['REQUEST_METHOD'] === 'POST' ||
($_SERVER['REQUEST_METHOD'] === 'GET' &&
($script == 'del_entry.php' ||
$script == 'add_entry.php' || $script == 'docdel.php' ||
endsWith($script, "_handler.php")))) {
//echo "KEY CHECK <br>\n";
$formKey = $_REQUEST['csrf_form_key'];
if ($formKey == $_SESSION['csrf_form_key'] && !empty($_SESSION['csrf_form_key'])) {
// Okay to proceed
//echo "FORM KEY: $formKey \n"; exit;
} else {
die_miserable_death ( translate ( 'Fatal Error' ) . ': '
. translate ( 'Invalid form request' ) );
}
}
//echo "METHOD " . $_SERVER['REQUEST_METHOD'] . "<br>";
//echo "PHP_SELF " . $script . "<br>";
//print_r ( $_SERVER );
//echo "NO ERROR <br>\n"; exit;

if ( is_array ( $instr ) ) {
for ( $j = 0; $j < count ( $instr ); $j++ ) {
// First, replace any escape characters like '\x3c'
Expand All @@ -41,7 +70,7 @@ function preventHacking ( $name, $instr ) {
}
if ( $failed ) {
die_miserable_death ( translate ( 'Fatal Error' ) . ': '
. translate ( 'Invalid data format for' ) . ' ' . $name .
. translate ( 'Invalid data format for' ) . '&nbsp;' . $name .
'<br>Value: ' . htmlspecialchars($instr));
}
} else {
Expand All @@ -62,6 +91,38 @@ function preventHacking ( $name, $instr ) {
}
}

// Function to check the string is ends
// with given substring or not
function endsWith($string, $endString)
{
$len = strlen($endString);
if ($len == 0) {
return true;
}
return (substr($string, -$len) === $endString);
}

/**
* Generate a key to include in HTML form to prevent CSRF.
*/
function getFormKey() {
if (!isset($_SESSION['csrf_form_key'])) {
$formKey = bin2hex(openssl_random_pseudo_bytes(32));
$_SESSION['csrf_form_key'] = $formKey;
} else {
$formKey = $_SESSION['csrf_form_key'];
}
return $formKey;
}

function csrf_form_key() {
return '<input type="hidden" name="csrf_form_key" value="' .
getFormKey() . '" />' . "\n";
}
function print_form_key() {
echo csrf_form_key ();
}


/**
* Gets the value resulting from an HTTP POST method.
Expand Down Expand Up @@ -103,15 +164,16 @@ function getPostValue($name, $defVal = NULL, $chkXSS = false)
*
* @see getPostValue
*/
function getGetValue($name)
function getGetValue($name, $devVal=NULL, $chkCSS=false)
{
$getName = null;
if (isset($_GET) && is_array($_GET) && isset($_GET[$name])) {
$getName = is_array($_GET[$name]) ? array_map('addslashes', $_GET[$name]) :
addslashes($_GET[$name]);
}
$cleanXSS = $chkXSS ? chkXSS($getName) : true;
preventHacking($name, $getName);
return $getName;
return $cleanXSS ? $postName : NULL;
}

/**
Expand Down Expand Up @@ -190,9 +252,7 @@ function chkXSS($name) {
global $login;
$cleanXSS = true;
//add more array elements as needed
foreach (array(
'Ajax.Request',
'onerror') as $i) {
foreach (array( 'Ajax.Request', 'onerror') as $i) {
if (preg_match("/$i/i", $name)) {
activity_log(0, $login, $login, SECURITY_VIOLATION,
'Hijack attempt:' . $i);
Expand Down

0 comments on commit d9729b4

Please sign in to comment.