Skip to content

Commit

Permalink
Added some security features (#262)
Browse files Browse the repository at this point in the history
* improved db connection opening

* removed default username from login form

* introduced csrf_token creation on session start
improved session security (httponly flag)
applied csrf_token on login
made some other minor fixes

* improved session management
  • Loading branch information
filippolauria committed Oct 6, 2022
1 parent c0dc4db commit 765fb6a
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 96 deletions.
104 changes: 54 additions & 50 deletions dologin.php
Expand Up @@ -27,72 +27,76 @@
include('library/sessions.php');
include_once('library/config_read.php');

// set's the session max lifetime to 3600 seconds
ini_set('session.gc_maxlifetime', 3600);

dalo_session_start();
dalo_session_regenerate_id();

$errorMessage = '';

// we need to set location name session variable before opening the database
// since the whole point is to authenticate to a spefific pre-defined database server

// validate location
$location_name = (!empty($_POST['location'])) ? $_POST['location']: "default";

/*
$_SESSION['location_name'] = (array_key_exists('CONFIG_LOCATIONS', $configValues)
&& is_array($configValues['CONFIG_LOCATIONS'])
&& count($configValues['CONFIG_LOCATIONS']) > 0
&& in_array($location_name, $configValues['CONFIG_LOCATIONS'])) ?
$location_name : "default";
*/

$_SESSION['location_name'] = isset($configValues['CONFIG_LOCATIONS'][$location_name]) ? $location_name : 'default';

include('library/opendb.php');
$location_name = (array_key_exists('location', $_POST) && isset($_POST['location']))
? $_POST['location']
: "default";

// we initialize some session params that will be useful later
$_SESSION['location_name'] = (array_key_exists('CONFIG_LOCATIONS', $configValues) &&
is_array($configValues['CONFIG_LOCATIONS']) &&
count($configValues['CONFIG_LOCATIONS']) > 0 &&
array_key_exists($location_name, $configValues['CONFIG_LOCATIONS']))
? $location_name
: "default";

$_SESSION['daloradius_logged_in'] = false;

// we interact with the db, ONLY IF user provided
// both operator_user and operator_pass params
if (array_key_exists('csrf_token', $_POST) && isset($_POST['csrf_token']) &&
dalo_check_csrf_token($_POST['csrf_token']) &&
array_key_exists('operator_user', $_POST) && isset($_POST['operator_user']) &&
array_key_exists('operator_pass', $_POST) && isset($_POST['operator_pass'])) {

include('library/opendb.php');

$operator_user = $dbSocket->escapeSimple($_POST['operator_user']);
$operator_pass = $dbSocket->escapeSimple($_POST['operator_pass']);

$sqlFormat = "select * from %s where username='%s' and password='%s'";
$sql = sprintf($sqlFormat, $configValues['CONFIG_DB_TBL_DALOOPERATORS'], $operator_user, $operator_pass);
$res = $dbSocket->query($sql);
$numRows = $res->numRows();

// we only accept ONE AND ONLY ONE RECORD as result
if ($numRows === 1) {
$row = $res->fetchRow(DB_FETCHMODE_ASSOC);
$operator_id = $row['id'];

$operator_user = $dbSocket->escapeSimple($_POST['operator_user']);
$operator_pass = $dbSocket->escapeSimple($_POST['operator_pass']);

$sqlFormat = "select * from %s where username='%s' and password='%s'";
$sql = sprintf($sqlFormat, $configValues['CONFIG_DB_TBL_DALOOPERATORS'],
$operator_user, $operator_pass);
$res = $dbSocket->query($sql);
$numRows = $res->numRows();
$_SESSION['daloradius_logged_in'] = true;
$_SESSION['operator_user'] = $operator_user;
$_SESSION['operator_id'] = $operator_id;

// lets update the lastlogin time for this operator
$now = date("Y-m-d H:i:s");
$sqlFormat = "update %s set lastlogin='%s' where username='%s'";
$sql = sprintf($sqlFormat, $configValues['CONFIG_DB_TBL_DALOOPERATORS'], $now, $operator_user);
$res = $dbSocket->query($sql);

if ($numRows != 1) {
$_SESSION['daloradius_logged_in'] = false;
$_SESSION['operator_login_error'] = true;
}

// ~ close connection to db before redirecting
// close connection to db before redirecting
include('library/closedb.php');

header('Location: login.php');
exit;
}

$row = $res->fetchRow(DB_FETCHMODE_ASSOC);
$operator_id = $row['id'];

if (array_key_exists('operator_login_error', $_SESSION)) {
unset($_SESSION['operator_login_error']);
}
$_SESSION['daloradius_logged_in'] = true;
$_SESSION['operator_user'] = $operator_user;
$_SESSION['operator_id'] = $operator_id;

// lets update the lastlogin time for this operator
$now = date("Y-m-d H:i:s");
$sqlFormat = "update %s set lastlogin='%s' where username='%s'";
$sql = sprintf($sqlFormat,
$configValues['CONFIG_DB_TBL_DALOOPERATORS'], $now, $operator_user);
$res = $dbSocket->query($sql);
// if everything went fine daloradius_logged_in session param has been set to true,
// so we can check it for deciding where and how redirect user browser
$header_location = "index.php";

// ~ close connection to db before redirecting
include('library/closedb.php');
if ($_SESSION['daloradius_logged_in'] !== true) {
$header_location = "login.php";
$_SESSION['operator_login_error'] = true;
}

header('Location: index.php');
header("Location: $header_location");

?>
57 changes: 20 additions & 37 deletions library/opendb.php
Expand Up @@ -20,58 +20,41 @@
*********************************************************************************************************
*/

include (dirname(__FILE__).'/config_read.php');
include (dirname(__FILE__).'/tableConventions.php');
include(dirname(__FILE__) . '/config_read.php');
include(dirname(__FILE__) . '/tableConventions.php');

// setup database connection information according to the session's location name which is held in $SESSION['location_name'].
// this is introduced in order to provide daloRADIUS to authenticate and manage several database backends without having to
// install several web directories of daloradius

if ((isset($_SESSION['location_name'])) && ($_SESSION['location_name'] != "default")) {
$location = (array_key_exists('location_name', $_SESSION) &&
isset($_SESSION['location_name']) &&
$_SESSION['location_name'] != "default")
? $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]
: "";

$mydbEngine = $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]['Engine'];
$mydbUser = $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]['Username'];
$mydbPass = $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]['Password'];
$mydbHost = $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]['Hostname'];
$mydbPort = $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]['Port'];
$mydbName = $configValues['CONFIG_LOCATIONS'][$_SESSION['location_name']]['Database'];

$dbConnectString = $mydbEngine . "://".$mydbUser.":".$mydbPass."@".
$mydbHost.":".$mydbPort."/".$mydbName;
} else {
// TODO
// requires handling of un-initialized session variable incase opendb.php is called not inside
// a session for some reason. requires further handling, possibly a log file entry
//exit;

$mydbEngine = $configValues['CONFIG_DB_ENGINE'];
$mydbUser = $configValues['CONFIG_DB_USER'];
$mydbPass = $configValues['CONFIG_DB_PASS'];
$mydbHost = $configValues['CONFIG_DB_HOST'];
$mydbPort = $configValues['CONFIG_DB_PORT'];
$mydbName = $configValues['CONFIG_DB_NAME'];

$dbConnectString = $mydbEngine . "://".$mydbUser.":".$mydbPass."@".
$mydbHost.":".$mydbPort."/".$mydbName;
}
$mydbEngine = ($location) ? $location['Engine'] : $configValues['CONFIG_DB_ENGINE'];
$mydbUser = ($location) ? $location['Username'] : $configValues['CONFIG_DB_USER'];
$mydbPass = ($location) ? $location['Password'] : $configValues['CONFIG_DB_PASS'];
$mydbHost = ($location) ? $location['Hostname'] : $configValues['CONFIG_DB_HOST'];
$mydbPort = ($location) ? $location['Port'] : $configValues['CONFIG_DB_PORT'];
$mydbName = ($location) ? $location['Database'] : $configValues['CONFIG_DB_NAME'];

$dbConnectString = sprintf("%s://%s:%s@%s:%s/%s", $mydbEngine, $mydbUser, $mydbPass, $mydbHost, $mydbPort, $mydbName);

// we introduced support for php's database abstraction layer which simplifies database connections
// to different technologies like mysql, oracle, postgresql, etc...
// until everything is completely migrated we will leave these commented out

include_once ('DB.php');
include_once('DB.php');

$dbSocket = DB::connect($dbConnectString);

if (DB::isError ($dbSocket))
die ("<b>Database connection error</b><br/>
<b>Error Message</b>: " . $dbSocket->getMessage () . "<br/>"
);

if (DB::isError($dbSocket)) {
die(sprintf("<b>Database connection error</b><br/><b>Error Message</b>: %s<br/>", $dbSocket->getMessage()));
}

include_once (dirname(__FILE__).'/errorHandling.php'); // we declare the errorHandler() function in errorHandling.php
include_once(dirname(__FILE__) . '/errorHandling.php'); // we declare the errorHandler() function in errorHandling.php

$dbSocket->setErrorHandling(PEAR_ERROR_CALLBACK, 'errorHandler'); // setting errorHandler function for the dbSocket obj

$dbSocket->query("SET SESSION sql_mode = '';");
$dbSocket->query("SET SESSION sql_mode = '';");
48 changes: 42 additions & 6 deletions library/sessions.php
Expand Up @@ -24,20 +24,54 @@
*******************************************************************************
*/

// this function ("installs" and) returns a csrf token
function dalo_csrf_token() {

$random = (function_exists('random_bytes'))
? random_bytes(32)
: ((function_exists('mcrypt_create_iv')) ? mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)
: openssl_random_pseudo_bytes(32));
$_SESSION['csrf_token'] = bin2hex($random);

return $_SESSION['csrf_token'];
}

// this function can be used for verifying if the csrf token is valid
function dalo_check_csrf_token($token) {
if (empty($token)) {
return false;
}

return hash_equals($_SESSION['csrf_token'], $token);
}

// daloRADIUS session start function support timestamp management
function dalo_session_start() {
ini_set('session.use_strict_mode', 0);
// set's the session max lifetime to 3600 seconds
ini_set('session.gc_maxlifetime', 3600);
ini_set('session.use_strict_mode', 1);

// Change PHPSESSID for better security, remove this if set in php.ini
session_name('daloradius_sid');

// Secure session_set_cookie_params
session_set_cookie_params(0, '/', null, null, true);

session_start();

if (array_key_exists('deleted_time', $_SESSION)) {
$t = $_SESSION['deleted_time'];
$now = time();

if (array_key_exists('time', $_SESSION) && isset($_SESSION['time'])) {
// if too old, destroy and restart
if (!empty($t) && $t < time()-900) {
session_destroy();
if ($_SESSION['time'] < $now-900) {
dalo_session_destroy();
session_start();
dalo_session_regenerate_id();
}
} else {
$_SESSION['time'] = $now;
}

}

// daloRADIUS session regenerate id function
Expand All @@ -50,14 +84,16 @@ function dalo_session_regenerate_id() {
$session_id = (function_exists('session_create_id'))
? session_create_id('daloRADIUS-') : uniqid('daloRADIUS-');

$_SESSION['deleted_time'] = time();
$_SESSION['time'] = time();

session_commit();

ini_set('session.use_strict_mode', 0);
session_id($session_id);

ini_set('session.use_strict_mode', 1);
session_start();

}

// daloRADIUS session destroy and clean all session variables
Expand Down
10 changes: 7 additions & 3 deletions login.php
Expand Up @@ -29,6 +29,7 @@
exit;
}

// this include "exports" $langCode that can be used in this script
include("lang/main.php");

// ~ used later for rendering location select element
Expand Down Expand Up @@ -74,7 +75,7 @@

<label for="operator_user">Username</label>
<input class="form-input" id="operator_user"
name="operator_user" value="administrator"
name="operator_user" value=""
type="text" tabindex="1" />

<label for="operator_pass">Password</label>
Expand All @@ -86,18 +87,21 @@
<select id="location" name="location" tabindex="3"
class="form-input"<?= ($onlyDefaultLocation) ? " disabled" : "" ?>>
<?php
$defaultLocationFormat = '<option value="%s">%s</option>' . "\n";
if ($onlyDefaultLocation) {
echo "<option value=\"default\">default</option>\n";
printf($defaultLocationFormat, "default", "default");
} else {
$locations = array_keys($configValues['CONFIG_LOCATIONS']);
foreach ($locations as $location) {
echo "<option value=\"$location\">$location</option>\n";
printf($defaultLocationFormat, $location, $location);
}
}
?>
</select>
<input class="form-submit" type="submit"
value="<?= t('text','LoginPlease') ?>" tabindex="4" />

<input name="csrf_token" type="hidden" value="<?= dalo_csrf_token() ?>" />
</form>

<small class="form-caption"><?= t('all','daloRADIUS') ?></small>
Expand Down

0 comments on commit 765fb6a

Please sign in to comment.