Nonce
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user user_id="0" status="1" access="2">
<user_name>jackJack23</user_name>
<user_pass><![CDATA[$2y$10$qSnm/ii1nRgLMICFP2ta0ueb5SWPUhgboB.59nMjgI472BubweEIi]]></user_pass>
</user>
</users>
Top
<style type="text/css">
.flex_wrap {display:flex;flex-flow:row wrap;}
.sel_control {margin:1rem;border:1px solid #000;border-radius:0.25rem;padding:0.25rem;}
.btn_control {margin:1rem;border:1px solid #000;border-radius:0.25rem;padding:0.25rem 0.5rem;background-color:#000;color:#fff;}
#user_message {margin:1rem;border:1px solid #000;border-radius:0.25rem;padding:0.25rem 0.5rem;min-height:10rem;}
</style>
Top
<?php
require_once('nonce.php');
$nonce = new Nonce();
$token = $nonce->generateNonce(10, 'form_login', 1);
?>
...
<form id="form_login" name="form_login">
<input type="hidden" id="nonce_token" name="nonce_token" value="<?php echo $token; ?>" />
<div class="flex_wrap">
<input type="text" id="txtUsername" name="txtUsername" class="sel_control" minlength="8" maxlength="20" placeholder="Username" />
<input type="password" id="txtPassword" name="txtPassword" class="sel_control" minlength="8" maxlength="20" placeholder="Password" />
<input type="button" id="btnRegister" value="Register" class="btn_control" />
<input type="button" id="btnLogin" value="Login" class="btn_control" /><br/>
</div>
<div id="user_message"></div>
</form>
Top
<script>
window.addEventListener("DOMContentLoaded", (event) =>{
let txtUsername = document.getElementById("txtUsername");
let txtPassword = document.getElementById("txtPassword");
let btnLogin = document.getElementById("btnLogin");
let btnRegister = document.getElementById("btnRegister");
let user_message = document.getElementById("user_message");
let nonce_token = document.getElementById("nonce_token");
btnRegister.addEventListener("click", function() {
let error_str = validate_login();
let data = "";
let msg = "";
let accessLevel = -1;
let xmlhttp;
let return_obj;
if (error_str == "") {
// PACKAGE THE DATA
data = "txtUsername="+ txtUsername.value +"&txtPassword="+ txtPassword.value + "&nonce_token="+ nonce_token.value;
if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); }
else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
/* 'errorString' => $error_str,
'userName' => $txtUsername,
'infoStr' => $info_str,
'userId' => $largest_id,
'accessLevel' => 2);
*/
returnObj = JSON.parse(xmlhttp.responseText);
if (returnObj.errorString != "") {
msg = "Error: "+ returnObj.errorString;
} else {
msg += returnObj.userName +"<br/>ID: "+ returnObj.userId +"<br/>"+ returnObj.infoStr +"<br/>";
accessLevel = parseInt(returnObj.accessLevel);
switch (accessLevel) {
case 0:
msg += "Registered as Adminitrator";
break;
case 1:
msg += "Registered as Manager";
break;
case 2:
msg += "Registered as User";
break;
default:
msg += "not registered";
}
}
user_message.innerHTML = msg;
}
}
xmlhttp.open("POST","notes_php6_back1.php",true);
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xmlhttp.send(data);
} else {
user_message.innerHTML = error_str
}
},false);
btnLogin.addEventListener("click", function() {
let error_str = validate_login();
let data = "";
let msg = "";
let accessLevel = -1;
let xmlhttp;
let return_obj;
if (error_str == "") {
// PACKAGE THE DATA
data = "txtUsername="+ txtUsername.value +"&txtPassword="+ txtPassword.value + "&nonce_token="+ nonce_token.value;
if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); }
else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
returnObj = JSON.parse(xmlhttp.responseText);
if (returnObj.errorString != "") {
msg = "Error: "+ returnObj.errorString;
} else {
msg += returnObj.userName +"<br/>User ID: "+ returnObj.userId +"<br/>"+ returnObj.infoStr +"<br/>";
accessLevel = parseInt(returnObj.accessLevel);
switch (accessLevel) {
case 0:
msg += "Logged in as Adminitrator";
break;
case 1:
msg += "Logged in as Manager";
break;
case 2:
msg += "Logged in as User";
break;
default:
msg += "Not logged in";
}
msg += "<br/>"+ returnObj.userMenu;
}
user_message.innerHTML = msg;
}
}
xmlhttp.open("POST","notes_php6_back2.php",true);
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xmlhttp.send(data);
} else {
user_message.innerHTML = error_str;
}
},false);
let validate_login = function() {
let error_str = "";
if (txtUsername.value.trim() == "") {
error_str += "You must enter a username<br/>";
} else {
if (txtUsername.value.length < 8) {
error_str += "Your username must be at least 8 characters long<br/>";
}
}
if (txtPassword.value.trim() == "") {
error_str += "You must enter a password<br/>";
} else {
if (txtPassword.value.length < 8) {
error_str += "Your password must be at least 8 characters long<br/>";
}
}
return error_str;
};
});
</script>
Top
The following code is code modified from code created by Simon Ugorji
<?php
// NONCE LIBRARY
session_start();
define('NONCE_SECRET', 'LaD^gEPr7#0oT$!s%KqHkM$^');
class Nonce {
/************************************************************************************************
* GENERATE SALT
*/
private function generateSalt($length = 10){
// SET UP RANDOM CHARACTERS
$chars='1uiop2rty34e5678fTYUIOPA90qwSDFGHcvbWEjkRJKLasdZXnmQghlzxCVBNM';
$char_len = strlen($chars)-1; // GET THE LENGTH OF THE RANDOM CHARACTERS
$output = '';
while (strlen($output) < $length) {
// GET RANDOM CHARACTERS AND APPEND TO OUTPUT UNTIL OUTPUT > $length
$output .= $chars[ rand(0, $char_len) ];
}
return $output;
}
/************************************************************************************************
* STORE NONCE
*/
private function storeNonce($form_id, $nonce){
// ARGUMENT MUST BE A STRING
if (is_string($form_id) == false) {
throw new InvalidArgumentException("A valid Form ID is required");
}
// GROUP GENERATED NONCES AND STORE WITH md5 HASH
$_SESSION['nonce'][$form_id] = md5($nonce);
return true;
}
/************************************************************************************************
* GENERATE NONCE
*/
public function generateNonce($length = 10, $form_id, $expiry_time){
$secret = NONCE_SECRET;
// SECRET MUST BE VALID. YOU CAN ADD YOUR regExp HERE
if (is_string($secret) == false || strlen($secret) < 10) {
throw new InvalidArgumentException("A valid Nonce Secret is required");
}
$salt = self::generateSalt($length); // GENERATE SALT
$time = time() + (60 * intval($expiry_time)); // CONVERT TIME TO SECONDS
$toHash = $secret.$salt.$time; // CONCATENATE TOKENS TO HASH
// SEND THIS TO THE USER WITH THE HASHED TOKENS
$nonce = $salt .':'.$form_id.':'.$time.':'.hash('sha256', $toHash);
self::storeNonce($form_id, $nonce); // STORE NONCE
return $nonce; // RETURN NONCE
}
/************************************************************************************************
* VERIFY NONCE
*/
public function verifyNonce($nonce){
$secret = NONCE_SECRET;
$split = explode(':', $nonce); // SPLIT NONCE WITH COLON DELIMETER
if (count($split) !== 4) { // CHECK IF THE COUNT EQUALS 4
return false;
}
$salt = $split[0]; // SEPARATE SALT
$form_id = $split[1]; // SEPARATE FORM ID
$time = intval($split[2]); // SEPARATE TIME
$oldHash = $split[3]; // SEPARATE OLD HASH
if (time() > $time) { // CHECK IF THE TIME HAS EXPIRED
return false;
}
if (isset($_SESSION['nonce'][$form_id])) { // CHECK IF NONCE IS PRESENT IN THE SESSION
if ($_SESSION['nonce'][$form_id] !== md5($nonce)) { // CHECK IF HASHED VALUE MATCHES
return false;
}
} else {
return false;
}
// CHECK THE NONCE AGAINST $oldHash
$toHash = $secret.$salt.$time;
$reHashed = hash('sha256', $toHash);
// MATCH WITH THE TOKEN
if ($reHashed !== $oldHash) {
return false;
}
return true; // NONCE IS VALID
}
}
?>
Top
<?php
require_once('nonce.php');
// GET THE POSTED DATA - reg_add.php
$txtUsername = $_POST['txtUsername'];
$txtPassword = $_POST['txtPassword'];
$nonce_token = $_POST['nonce_token'];
$error_str = '';
$info_str = '';
$nonce = new Nonce();
if ($nonce->verifyNonce($nonce_token)) {
$xml_file = 'site_users_nd1.xml';
$counter = 0;
$info_str = 'Nonce Passed. ';
/*
* users
* user user_id status access
* user_name
* user_pass
*/
if (file_exists($xml_file)) {
$info_str .= 'File exists. ';
$current_id = -1;
$new_id = 0;
$domDoc = new DOMDocument(); // CREATE A DOM DOCUMENT TO LOAD XML FILE DATA INTO
$domDoc->preserveWhiteSpace = false; // SET PRESERVE WHITESPACE TO FALSE
$domDoc->formatOutput = true; // MAKE OUTPUT FORMATTED WITH INDENTED CODE
$domDoc->load($xml_file); // LOAD THE FILE DATA INTO THE DOM DOCUMENT
$xpath = new DOMXPath($domDoc); // CREATE A NEW DOMXPath OBJECT FROM THE XML DOCUMENT
$theDoc = $domDoc->documentElement;
/* LOOP THROUGH ALL OF THE user NODES */
foreach($domDoc->getElementsByTagName('user') as $user) {
$current_id = $user->getAttribute('user_id');
if ($current_id > $new_id) {
$new_id = $current_id;
}
if ($user->getElementsByTagName('user_name')->item(0)->nodeValue == $txtUsername) {
$error_str = 'Error: Username Already Exists';
}
}
if ($error_str == "") {
$new_id++;
$user = $domDoc->createElement('user');
$user->setAttribute( 'user_id', $new_id );
$user->setAttribute( 'status', '1' ); // ACTIVE
$user->setAttribute( 'access', '2' ); // BASIC NON USER - TO BE MANUALLY EDITED
$user_name = $domDoc->createElement('user_name', $txtUsername);
$user_pass = $domDoc->createElement('user_pass'); // USER_PASS
$user_pass->appendChild($domDoc->createCDataSection(password_hash($txtPassword, PASSWORD_DEFAULT)));
// APPEND USER_NAME TO USER
$user->appendChild( $user_name );
// APPEND USER_PASS TO USER
$user->appendChild( $user_pass );
// APPEND USER TO USERS
$theDoc->appendChild( $user );
// SAVE IN FILE "xml_users.xml"
$domDoc->save($xml_file);
$info_str .= 'User: '. $txtUsername .' registered. ';
}
} else {
$info_str .= 'File does not exist. ';
$new_id = 0;
/* FILE DOES NOT EXIST, SO CREATE XML TO BE SAVED TO FILE */
$domDoc = new DomDocument('1.0', 'UTF-8');
$domDoc->preserveWhiteSpace = false;
$domDoc->formatOutput = true;
// ADD ROOT ELEMENT
$users = $domDoc->appendChild($domDoc->createElement('users'));
// CREATE USER NODE
$user = $domDoc->createElement('user');
$user->setAttribute( 'user_id', '0' ); // FIRST USER
$user->setAttribute( 'status', '1' ); // ACTIVE
$user->setAttribute( 'access', '2' ); // BASIC NON USER - TO BE MANUALLY EDITED
$user_name = $domDoc->createElement('user_name', $txtUsername);
$user_pass = $domDoc->createElement('user_pass'); // USER_PASS
$user_pass->appendChild($domDoc->createCDataSection(password_hash($txtPassword, PASSWORD_DEFAULT)));
// APPEND USER_NAME TO USER
$user->appendChild( $user_name );
// APPEND USER_PASS TO USER
$user->appendChild( $user_pass );
// APPEND USER TO USERS
$users->appendChild( $user );
// SAVE IN FILE "xml_users.xml"
$domDoc->save($xml_file);
$info_str .= 'New file created. User: '. $txtUsername .' registered. ';
}
} else {
$error_str = 'Nonce Failed';
}
$output = array('errorString' => $error_str,
'infoStr' => $info_str,
'userName' => $txtUsername,
'userId' => $new_id,
'accessLevel' => 2);
header('Content-Type:application/json');
echo json_encode($output, JSON_FORCE_OBJECT);
?>
Top
<?php
require_once('nonce.php');
$txtUsername = $_POST['txtUsername'];
$txtPassword = $_POST['txtPassword'];
$nonce_token = $_POST['nonce_token'];
$error_str = '';
$info_str = '';
$nonce = new Nonce();
if ($nonce->verifyNonce($nonce_token)) {
$xml_file = 'site_users_nd1.xml';
$counter = 0;
$info_str = 'Nonce Passed. ';
$menu_str = '';
$access_level = -1;
$user_id = -1;
/*
* users
* user user_id status access
* user_name
* user_pass
*/
if (file_exists($xml_file)) {
$domDoc = new DOMDocument(); // CREATE A DOM DOCUMENT TO LOAD XML FILE DATA INTO
$domDoc->preserveWhiteSpace = false; // SET PRESERVE WHITESPACE TO FALSE
$domDoc->formatOutput = true; // MAKE OUTPUT FORMATTED WITH INDENTED CODE
$domDoc->load($xml_file); // LOAD THE FILE DATA INTO THE DOM DOCUMENT
foreach($domDoc->getElementsByTagName('user') as $user) {
if ($user->getElementsByTagName('user_name')->item(0)->nodeValue == $txtUsername) {
if (password_verify($txtPassword, $user->getElementsByTagName('user_pass')->item(0)->nodeValue)) {
// START A SESSION
//session_start();
$access_level = (int)$user->getAttribute('access');
$user_id = (int)$user->getAttribute('user_id');
$_SESSION['access'] = $access_level;
$_SESSION['sid'] = $user_id;
$_SESSION['user_name'] = $txtUsername;
switch($access_level) {
case 0 :
$menu_str = '<a href="#" class="btn btn-bs-primary">Admin Page</a>';
break;
case 1 :
$menu_str = '<a href="#" class="btn btn-bs-primary">Manager Page</a>';
break;
case 2 :
$menu_str = '<a href="#" class="btn btn-bs-primary">User Page</a>';
break;
default:
$menu_str = '';
}
}
}
}
if ($access_level == -1) {
$error_str = 'Login Failed';
}
} else {
$error_str = 'File Does Not Exist';
}
} else {
$error_str = 'Nonce Failed';
}
$output = array('errorString' => $error_str,
'userName' => $txtUsername,
'infoStr' => $info_str,
'userId' => $user_id,
'userMenu' => $menu_str,
'accessLevel' => $access_level);
header('Content-Type:application/json');
echo json_encode($output, JSON_FORCE_OBJECT);
?>
Top