Skip to content

Instantly share code, notes, and snippets.

@nightmarecake
Last active May 17, 2016 13:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nightmarecake/103af39018f7400e82777046ebccbacb to your computer and use it in GitHub Desktop.
Save nightmarecake/103af39018f7400e82777046ebccbacb to your computer and use it in GitHub Desktop.
code sample 1
<?php
//The following code begins a session. It should be included in every page of the website.
//This PHP file should be the first thing on a page (imported using 'include'), before any headers or output at all is loaded.
//Forces sessions to only use cookies.
//Makes sure that the value in the php.ini file of session.use_only_cookies' is equal to 1 so that hackers can't use a URL instead.
if (ini_set('session.use_only_cookies', 1) === FALSE) {
header("Location: ../error.php?err=Could not initiate a safe session (ini_set)");
exit(); }
//gets current cookies params
//Returns an array with the current session cookie information, the array contains the following items:
//"lifetime" - The lifetime of the cookie in seconds.
//"path" - The path where information is stored.
//"domain" - The domain of the cookie.
//"secure" - The cookie should only be sent over secure connections.
//"httponly" - The cookie can only be accessed through the HTTP protocol.
$cookieParams = session_get_cookie_params();
//sets the cookie params for the session to be secure=false (for http, not https) and httponly=true
//TODO: change this for clients who purchase an SSL certificate. Change the param for "secure" to be "true".
session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], false, true);
session_name('secure_session_001'); // Sets a unique session name
session_start(); // Starts the PHP session
session_regenerate_id(true); // regenerates the session, deleting the old one.
//imports the mysqli variable - this adds security by keeping the SQL password and credentials in a seperate file,
//and adds ease-of-use - in case the credentials need to be changed, only this one external file would need to be edited.
include($_SERVER['DOCUMENT_ROOT'] . "/mysqli_cake.php");
/*
My website keeps 1 "remember me" cookie permanently inside the user's computer.
For every registered user, a copy of this cookie can be found in the online database.
This cookie can take on the following values:
0 = not logged in, for sure.
1 = logged in, "remember me" isn't checked OR may be logged out but cookie not updated. In this case, use session cookie to verify whether a user is logged in, and do not use this "remember me" cookie to verify whether or not a user is logged in.
username_f5bdad87cab1e9a6f0765df6...... = username + underscore + a random 128bit hexadecimal number Only if the cookie takes on this form, should it ever be used to attempt to check if a user is currently logged in already.
This token is generated differently for each login, and recorded in the database as well as on the user's computer.
This username/number combination can be used to check against the database to see if the user can be automatically authenticated.
If this cookie is stolen by a third party, it can let them log in to the account. So when this cookie is sent over a network, it should be ssl encrypted.
TODO: store cookie in database as a hash, because if a hacker gets access to the cookies in my database, they are a login credential they can use to access accounts.
This username/number combination should not be saved on a public computer. This is done by not checking "remember me" on a public computer.
When a user logs out, both the cookie on their computer and the cookie in my database goes back to 0. As soon as a user logs in again, this cookie changes to A DIFFERENT random token.
This way, if a user logs out and then back in again, the random token is completely different and any cookies on other computers that may have still have the old token, are invalidated.
*/
//This "login_check" function gets called once at the start of every page that includes this start_secure_session.php or includes the html_head.php.
//Basically - at the start of every single page, before headers have been sent out.
//It sets a variable that the entire page can use (server-side only, of course!)
$logged_in_ma_and_username = 0; //the default setting is 0, meaning "not logged in"
//the following function can change this variable's value to a username, and if it's a username, then that also means that the user is logged in.
login_check($logged_in_ma_and_username); //this function is defined below
function login_check(&$logged_in_ma_and_username) {
//The following function is designed to be used in two places:
//1)It shows up once at the forefront of every page, before any headers have been sent out. Even in every little mini ajax-loaded page, it is called.
// There, it not only checks to see if the user is logged in,
// but it also cleans up the cookies on the user's computer,
// and it also sets one variable to be used (server side only, of course) throughout the rest of the page:
//string $logged_in_ma_and_username
// This variable can be used both to know whether or not a user is logged in,
// and also to know their username without having to write a separate function to comb through the session variables and cookie variables exactly in the same way that this one does.
// if the user is logged in (doesn't matter whether through a cookie or through a session variable), then this variable is set to the user's username
// if the user is not logged in, this is set to 0. (Since all usernames are at least 4 characters long, there are no problems with 0 being someone's username.)
//2)It can also be used many additional times after the first, within any html code within any webpage on the whole site, not just when the headers are first sent out.
// This second time is used specifically to check whether a user is logged in, before they do any registered-user-only functions such as submitting a forum post.
// Usually this happens via ajax calls and therefore is on a special page without a Login Module, or there may be other reasons to do a "double check" before a submission.
//3)A small note. When the user first logs in, or when a user logs out, the entire page doesn't refresh. Only the ajax-loaded part refreshes.
// The old variables (meaning, the old content) will be there for the un-reloaded page, but the new variables (meaning new content) will be there just in the new module.
// Upon page reload, login_check() always WILL get called, and the entire page will have new variables (and therefore new content)
//Returns "true" if the user is logged in, returns "false" if the user is not logged in.
//Additionally, records these authentication attempts in the database.
//Although I've already mentioned this, it also cleans up the cookies on the user's computer.
//import the sql connection
global $mysqli;
$now = time(); //Gets timestamp of current time.
$user_ip_address = $_SERVER['REMOTE_ADDR']; // Gets the user's IP address.
$cookie_from_user_computer = 'x'; //a default value for the sanitized cookie variable taken from users computer
$cookie_from_the_database = 'x'; //a default value for the cookie variable taken from the database
$logged_in_ma_and_username = '0'; //This variable is a string! It has just been set to a default value for the username - 0 means "not logged in".
$cookie_failure = "0"; //a variable for testing reasons for no authentication from a cookie, in a non-production environment
//The following code block can prematurely authenticate a user thanks to a cookie.
if (isset($_COOKIE['remembered_session'])) { //if there is a cookie on the user's computer named 'remembered_session', then...
$cookie_from_user_computer = sanitize_data($_COOKIE['remembered_session']); //makes the contents of the cookie safe from injection and XSS
$logged_in_ma_and_username = substr($cookie_from_user_computer, 0, strrpos($cookie_from_user_computer , "_")); //figures out the username from the cookie
//the series of the statements after this one all depend on the cookie in the database NEVER being something other than
//a 1, a 0, or a username_3961396193196 type of string. Be very careful with the shit that's added to the database.
//if something like "3" is on the database, and the user has a spoofed "3" cookie (a very simple example...) this all falls apart.
//If a user has a spoofed cookie that has a match on the database, that's all they need, to log in.
//Therefore, cookies are very long and secure and super randomized. Also, I should buy an SSL certificate ):
if ( ($cookie_from_user_computer !="1") && ($cookie_from_user_computer !="0") ) { //if the cookie on the computer isn't a 1 or 0
//(meaning that then it is of username_401710470171 format or maybe a spoofed fake random format cookie), then...
//check the database to see if it has a match
if ($stmt = $mysqli->prepare("SELECT remember_me_cookie FROM users WHERE remember_me_cookie = ? LIMIT 1 ")) { //if this mysql query has successfully run, then ....
//get the value of the cookie in the database
$stmt->bind_param('s', $cookie_from_user_computer); //binds "$cookie_from_user_computer" to parameter
$stmt->execute(); //executes the prepared query.
$stmt->store_result();
$stmt->bind_result($cookie_from_the_database); //binds the result to "$cookie_from_the_database"
$stmt->fetch();
if ($stmt->num_rows == 1) { // If the two cookies match, then there will be 1 row result
//The following block adds this successful cookie login_check attempt to the database.
record_authentication_attempt($logged_in_ma_and_username, 'success', 'cookie on computer matches cookie in database upon login_check', $mysqli);
// Logged In!!!! This whole function is terminated and returns a value.
return true; }
else { //If there was not a 1-row result (meaning that the two cookies didnt match), then ...
//This invalid cookie-on-the-user's-computer should be changed to "1" (meaning that the user might be logged in through a session) right now
//Don't change the cookie on the database, though, or else random assholes will be able to delete random peoples' cookies from database.
if (!headers_sent()) { //this if-statement has been added just in case the function was used in a place where headers were already sent. No cleanup happens in that case.
//Not to worry though, the cleanup will happen upon next page refresh, because this function will be called once, before headers are sent, on ALL pages.
setcookie('remembered_session', '1', time() + (60 * 60 * 24 * 365), "/", ".endgame.pk"); }
//Don't return false yet. This just means that maybe let's check the session instead of the cookie. Maybe the user had an old cookie still in his browser.
//Do record this fail cookie login_check attempt to the database.
record_authentication_attempt($logged_in_ma_and_username, 'failure', 'cookie authentication failure - cookie on computer doesnt match cookie in database', $mysqli); } }
else { //if the mysql statement got rejected, then ...
//don't return false yet, because this just means that maybe lets check the session instead of the cookie
//I will not delete the user's cookie just because the mysql statement got rejected.
$cookie_failure = "1"; } } //for testing + note-to-self
else { //if the cookie on the computer is a 1 or 0 , then...
//don't return false yet, because this just means that maybe lets check the session instead of the cookie
$cookie_failure = "2"; } }
else { //if there was no cookie set, then ...
//set one -_- make it "1" (meaning that the user might be logged in through a session) right now
//Don't change the cookie on the database, though, or else random assholes will be able to delete random peoples' cookies from database.
if (!headers_sent()) { //this if-statement has been added just in case the function was used in a place where headers were already sent. No cleanup happens in that case.
//Not to worry though, the cleanup will happen upon next page refresh, because this function will be called once, before headers are sent, on ALL pages.
setcookie('remembered_session', '1', time() + (60 * 60 * 24 * 365), "/", ".endgame.pk"); }
//don't return false yet, because this just means that maybe lets check the session instead of the cookie
$cookie_failure = "3"; }
//The following runs if all session variables are set (they have to be set, for this to work!)
//it won't run if the if-statement above already "returned true" for this whole function,
//because then this whole function would have been terminated and the user would have been logged in through a cookie
//But it -will- run even if the above if-statement failed and DIDN'T authenticate the user prematurely, due to a cookie.
//The cookie may have been wrong and it has been reset back to "1".
//The user will now be attempted to be authenticated through a session.
if (isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string'])) {
$user_id = $_SESSION['user_id'];
$login_string = $_SESSION['login_string'];
$logged_in_ma_and_username = $_SESSION['username'];
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
if ($stmt = $mysqli->prepare("SELECT password FROM users WHERE id = ? LIMIT 1")) {
$stmt->bind_param('i', $user_id); // Bind "$user_id" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
if ($stmt->num_rows == 1) { //if the user exists, then...
$stmt->bind_result($password); //bind the password result to a variable
$stmt->fetch();
$login_check = hash('sha512', $password . $user_browser);
if ($login_check == $login_string) {
// Logged In!!!!
record_authentication_attempt($logged_in_ma_and_username, 'success', 'authenticated from a session variable', $mysqli);
//echo '<br>authenticated from a session variable on your computer<br>'; //this line is just for testing purposes
return true; }
else {
// Not logged in
record_authentication_attempt($logged_in_ma_and_username, 'failure', 'session variable authentication failure - login_check isnt equal to login_string', $mysqli);
$logged_in_ma_and_username = "0"; //set to zero after one is finished with using the username, to indicate "logged out".
return false; } }
else {
// Not logged in
record_authentication_attempt($logged_in_ma_and_username, 'failure', 'session variable authentication failure - sql query didnt return 1 row', $mysqli);
$logged_in_ma_and_username = "0"; //set to zero after one is finished with using the username, to indicate "logged out".
return false; } }
else {
// Not logged in
record_authentication_attempt($logged_in_ma_and_username, 'failure', 'session variable authentication failure - sql prepared statement didnt return true', $mysqli);
$logged_in_ma_and_username = "0"; //set to zero after one is finished with using the username, to indicate "logged out".
return false; } }
else {
// Not logged in
record_authentication_attempt($logged_in_ma_and_username, 'failure', 'session variable authentication failure - session variables not set', $mysqli);
$logged_in_ma_and_username = "0"; //set to zero after one is finished with using the username, to indicate "logged out".
return false; }
} //---END function definition of login_check
//Session cookie has been set. Session variables in database have been initialized.
//It is now safe to load headers/output.
//The above doesn't apply to the contents of some functions, though.
//For example, login() and logout() are designed to be called before headers are sent out.
//But if it's not part of a function, or relies on one of those special ones, yeah you can load headers/output now.
function login($username, $password, $remember_me, &$user_brute_force_msg, &$ip_brute_force_msg) {
//This function returns "true" upon successful username/password input, and "false" otherwise.
//If true, it also starts a session for that user.
//If true AND $remember_me is 1, it also sets a cookie in the user's browser that is an authentication code that can be used to automatically verify that the user is logged in.
//However, the vary important variables it outputs are the three reference vars. They will alert the user to various hacking attempts and show different messages on login screen.
//The function will output (bool) user_brute_force_msg = FALSE if the username did not have a ton of failed login attempts
//It will output (bool) user_brute_force_msg = TRUE if the username DID have a ton of failed login attempts
//This output can be used to know that a user is being targeted by other IP addresses, it could be used to tell that user, showing a special message.
//The function will output (string) ip_brute_force_msg = "0" if user does not have to wait any seconds to log in.
//It will output something like (string) ip_brute_force_msg = "120" (a number of seconds) if the user DOES have to wait to log in.
//The number in quotes (that string) is how many seconds they must wait.
//import the sql connection
global $mysqli;
$now = time(); // Get timestamp of current time
$user_ip_address = $_SERVER['REMOTE_ADDR']; // Get the user's IP address.
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, password, salt FROM users WHERE username = ? LIMIT 1")) {
$stmt->bind_param('s', $username); // Binds "$username" to parameter.
$stmt->execute(); // Executes the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $db_password, $salt);
$stmt->fetch();
// hash the password with the unique salt.
$password = hash('sha512', $password . $salt);
if ($stmt->num_rows == 1) { //if this if-clause is true, the inputted username exists.
//tbh, i should remove this if else clause pair, because I should be imposing this check OUTSIDE of this login function.
if (check_login_brute($mysqli)!=0) { //if this IP address has tried too many login attempts and has to wait any longer than 0 seconds...
//add this failed login attempt to the database
record_authentication_attempt($username, 'failure', 'too many login attempts', $mysqli);
//terminate function and don't let them log in
return false; }
else { //if this IP address hasn't tried too many attempts...
// Check if the password in the database matches
// the password the user submitted.
//echo 'location 2';
if ($db_password == $password) { //if this if-clause is true, the user's password is valid, and they can be logged in now
//The following code logs the user in by setting session variables on the server.
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
$user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we might print this value
$_SESSION['user_id'] = $user_id;
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); // XSS protection as we might print this value
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password . $user_browser);
if ($remember_me==1) { //if the user wants to be remembered
$cookie_value = $username."_".bin2hex(openssl_random_pseudo_bytes(128));
// set the database cookie reference number
if ($stmt = $mysqli->prepare("UPDATE users SET remember_me_cookie = ? WHERE username = ? ")) {
$stmt->bind_param('ss', $cookie_value, $username);
$stmt->execute(); }
//mysql_query("UPDATE users SET remember_me_cookie ='".$cookie_value."' WHERE username ='".$username."'") or die(mysql_error());
// set the user's computer cookie reference number
setcookie('remembered_session', $cookie_value, time() + (60 * 60 * 24 * 365), "/", ".endgame.pk"); }
else { //user doesn't want to be remembered
$cookie_value = "1"; //sets the cookie variable to 1 - "logged in but cookieless" (but havent yet applied this variable to the cookie on comptuer or database)
// set the database cookie reference number
if ($stmt = $mysqli->prepare("UPDATE users SET remember_me_cookie = ? WHERE username = ? ")) {
$stmt->bind_param('ss', $cookie_value, $username);
$stmt->execute(); }
//mysql_query("UPDATE users SET remember_me_cookie ='".$cookie_value."' WHERE username ='".$username."'") or die(mysql_error()); // set the online cookie reference number
// nvm it, for the line below - the cookie on the users computer - don't set a cookie at all. if there's no cookie then it means no cookie-authentication anyways
//setcookie($cookie_name, $cookie_value, time() + (60 * 60 * 24 * 365), "/", ".endgame.pk"); // 60 seconds (1 minute) x 60 minutes (1 hour) x 24 hours (1 day) x 365 days (1 year)
}
//Add this successful login attempt to the database
record_authentication_attempt($username, 'success', 'correct username/password combination upon login', $mysqli);
return true; }
else { //if the user's password is invalid...
//add this failed login attempt to the database
record_authentication_attempt($username, 'failure', 'the username exists, but the password was entered wrongly upon login', $mysqli);
//and end this function and return false
return false; }
} }
else { // if the username entered does not exist...
//add this failed login attempt to the database
record_authentication_attempt($username, 'failure', 'no such username', $mysqli);
//and end this function and return false
return false; } }
} //---END function definition of login
function should_captcha_ma() {
//Returns "true" if the person on this ip address SHOULD be prompted with a captcha.
//Returns "false" if the person on this ip address should NOT be required to input a captcha.
//import the sql connection
global $mysqli;
$user_ip_address = $_SERVER['REMOTE_ADDR']; //gets the user's IP address
$failcount = 0; //no failures counted yet
//Checks to see if a captcha should be imposed.
//Imposes one if all more than 5 out of the last 6 login attempts by this IP address were failures
if ($stmt = $mysqli->prepare("SELECT result FROM login_attempts WHERE ip_address = ? ORDER BY attempt_id DESC LIMIT 6 ")) {
$stmt->bind_param('s', $user_ip_address); //binds the variable to the parameters
$stmt->execute(); //executes the prepared query.
$stmt->bind_result($success_of_latest_attempt); //binds the result to a variable
while ($stmt->fetch()) { //while there are rows to fetch...
if ($success_of_latest_attempt == "failure") { //if any of the last 5 attempts to log in have been failures ...
//count the fails
$failcount++; } } }
else { //if the mysql statement got screwed
//force the user to solve a captcha
return true; }
if ($failcount >= 5) { //if there were at least 5 fail login attempts out of the last 6...
//force the user to solve a captcha
return true; }
else { //if less than 5 of the last 6 login attempts were failures ...
//thhe user doesn't have to solve a captcha
return false; }
}
function check_username_hack_massattack($username) {
//Returns "true" if more than 100 fail login attempts tried to get into that username's account in the last week.
//Returns "false" if there weren't.
//import the sql connection
global $mysqli;
$now = time(); //gets timestamp of current time
$last_week = time() - (60 * 60 * 24 * 7); //gets timestamp of the first second of 7-days-ago
//Checks to see if a user's ID has had a ton of failed login attempts (more than 100) recently (the past week).
//It might be by a lot of IP addresses or it might be by just a single IP address.
//Doesn't yet do anything to prevent this, but can tell the user that there ARE hacking attempts in progress.
//Here is an example of a message to output somewhere else, if 1 username has had a ton of login attempts over a series of many IP addresses:
// "Please note. Someone is using 1,000 different IP addresses to try and hack your account password.
// Even if I block thousands of chinese IP addresses, they will find thousands of new ones to attack people with.
// I'm using a better security measure to stop these guys from trying to hack you -
// I am limiting their hacking to just one pathetic attempt per 2 minutes, per server.
// If your password is something long with random dictionary words, like "correctbatteryhorsestaple" -
// Don't worry. YOU ARE SAFE AND DONT HAVE TO WORRY. Such a password would take billions of years to crack using even a dictionary method at 1,000 guesses every 2 minutes.
// But if you're using a short password like DeRp$ma ... you're toast. Go change it asap or the hackers will get you. "
//It would be good to show this message in a special "notice panel" on the user's screen somewhere up top.
//A panel that isn't ever visible unless there's a personal message like this, or a website-wide problem.
if ($stmt = $mysqli->prepare("SELECT attempt_id, time, ip_address FROM login_attempts WHERE username = ? AND time > ? AND result ='failure' ")) { // add later ... reason = login brute, not cookie brute,
$stmt->bind_param('ss', $username, $last_week); //binds parameters to statement
$stmt->execute(); //executes the prepared query.
$stmt->store_result();
if ($stmt->num_rows > 100) { // If there have been more than 100 failed attempts to log in to that username within the last week, then...
return true; }
else { // If there HAVEN'T been more than 100 failed attempts to log in to that username within the last week, then...
return false; } }
else { //if the mysql statement got rejected
//return false, to not scare the user unnecessarily
return false; }
//TODO: Add a script that will show all the successful logins for the user's ID, and show the IP address for each login.
//Also maybe show the unsuccessful logins for their ID if they wanna see the horrors ):
} //---END function definition of check_username_hack_massattack
function check_login_brute() {
//Returns an integer.
//Returns 0 if the user does not have to wait any seconds to log in.
//Otherwise, returns an integer 1-300, of how long they must wait before attempting to log in again.
//Returns "false" if these were no spam login attempts by that IP address. This is the only value required by other parts of the website to know if the user is allowed to try logging in or not.
//Returns "true" if there WERE spam login attempts by that IP address. This is the only value required by other parts of the website to know if the user is allowed to try logging in or not.
//However, the vary important variables it outputs are the three reference vars. They will alert the user to various hacking attempts and show different messages on login screen.
//This output can be used to know that a user is being targeted by other IP addresses, it could be used to tell that user, showing a special message.
//The function will output (string) ip_brute_force_msg = "0" if the function is about to return "false" and user does not have to wait any seconds to log in.
//It will output something like (string) ip_brute_force_msg = "120" (a number of seconds) if the function is about to return "true" and the user DOES have to wait to log in.
//The number in quotes (that string) is how many seconds they must wait.
//import the sql connection
global $mysqli;
$now = time(); //gets timestamp of current time
$five_minutes_ago = time() - (60 * 5); //gets timestamp of the first second of 5-minutes-ago
$user_ip_address = $_SERVER['REMOTE_ADDR']; //gets the user's IP address
$time_of_latest_failure = "0"; //A variable to store the timestamp of the latest failed login attempt. It has been set to a default of "0".
$success_of_latest_attempt = "0"; //A variable to store the result of some mysql queries later on in this code. It has been set to a default of "0".
//Checks to see if the IP address that is accessing the site right now, has had more than 5 failed attempts within the last 5 minutes.
//If it does, do not allow that IP address to attempt to log in. Record how many seconds they have to wait, until they can try and log in again.
//Another function can slap a captcha on top of that.
//this all wont even matter (except for bandwidth resources... but thats a ddos issue Q_Q) if the users just have correctbatteryhorsestaple passwords.
if ($stmt = $mysqli->prepare("SELECT time FROM login_attempts WHERE ip_address = ? AND time > ? AND result ='failure' ORDER BY attempt_id ASC")) {
$stmt->bind_param('ss', $user_ip_address, $five_minutes_ago);
$stmt->execute(); //executes the prepared query.
$stmt->store_result(); //stores the result
$stmt->bind_result($time_of_latest_failure); //binds the result to a variable
if ($stmt->num_rows >= 5) { //if there were at least 5 fail login attempts results in the last 5 minutes for this IP address, then...
$stmt->fetch(); //fetch the first row - the one with the smallest integer timestamp - meaning longest time ago
//This is how many seconds they have to wait before they can try to log in again.
//Add +1 at the end to stop a user from seeing a message like "you need to wait 0 more seconds to log in" when there's a mere fraction of a second left.
//echo 'now = '.$now.' latest fail= ' .$time_of_latest_failure;
return (300 - ($now - $time_of_latest_failure) + 1); }
else { //there were less than 5 fail login attempts in the last 5 minutes for this IP address
return 0; } }
else { //if the mysql query got screwed
//every possibility of this final if-block needs to end the function and return a value
return 60; }
} //---END function definition of check_login_brute
function check_cookie_brute() {
//I haven't decided a method of analysis for a hacker's multiple attempts on spoofing a legitimate user's session cookie or remember-me cookie.
}
function logout() {
//import the sql connection
global $mysqli;
//TODO: fix the below statements later. Used the old-school mysql connection by accident. it is depreciated
// Preferrably fix this by passing $mysqli into this function, and rewriting one of the below calls to the database
//First off, delete the session and the cookies associated with the session
//figure out the username
$username_gotten_from_session = '0';
if (isset($_SESSION['username'])) {
$username1 = sanitize_data($_SESSION['username']); }
// Unset all session values
// make sure that a user can't put in their computer a random ression name, and delete from server someone else's random session if it matches the name ... add code for this in the future ....
$_SESSION = array();
// get session parameters
$params = session_get_cookie_params();
// Delete the actual cookie.
setcookie(session_name(),
'', time() - 42000,
$params["path"],
$params["domain"],
$params["secure"],
$params["httponly"]);
// Destroy session
session_destroy();
//header('Location: ../index.php');
//secondly, delete cookie that allows the user to authenticate, from their computer
//figure out the username
$username_gotten_from_computer_cookie = '0';
$computer_cookie = '0';
if (isset($_COOKIE['remembered_session'])) {
$computer_cookie = sanitize_data($_COOKIE['remembered_session']);
$username_gotten_from_computer_cookie = substr($computer_cookie, 0, strrpos($computer_cookie, "_")); }
// after this, it would be ideal to set the database reference to the cookie in to "0" (aka, logged out), but this would allow hackers to
// spoof a random username before the underscore, and log random people out
// to counteract this, only connect to database and change the reference, if the cookie can be successfully authenticated first.
// THIS MEANS ALSO, HOWEVER, THAT USERS THAT HAVE NO COOKIE ON THEIR COMPUTER BECAUSE OF NO "remember me" CHECKED, WILL NOT GET A MATCH WITH THE DATABASE COOKIE, EITHER.
// THIS WILL CAUSE DATABASE COOKIES TO STILL BE SET TO "1" EVEN THOUGH THE USE HAS LOGGED OUT. So technically "1" means "the user definitely isnt logged in with a cookie".
if ($stmt = $mysqli->prepare("SELECT remember_me_cookie FROM users WHERE remember_me_cookie = ? LIMIT 1")) {
// Bind "$computer_cookie" to parameter.
$stmt->bind_param('s', $computer_cookie);
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
if ($stmt->num_rows == 1) { // If the two cookies match, then there will be 1 row result
// The following line changes the value of the database reference to the cookie used for session authentication. 0 means not logged in.
mysql_query("UPDATE users SET remember_me_cookie ='0' WHERE username ='".$username_gotten_from_computer_cookie."'") or die(mysql_error());
//$stmt->bind_result($cookie_from_the_database);
//echo 'the cookie in the database is '.$cookie_from_the_database.'<br>';
//$stmt->fetch();
//$login_check = hash('sha512', $password . $user_browser);
}
}
// no matter if authenticated or not, delete the cookie used for session authentication, on the computer.
setcookie('remembered_session', '', time() - 42000, "/", ".endgame.pk"); // set it to a negative time, to delete it, make sure to include all parameters
// it's important to write some more code here, to destroy all sessions that have the username of the person logging out, when this function is called.
// it will log out anyone logged in as that username anywhere, as opposed to just that 1 browser or that one computer.
}
function register($username, $password, $password_check, &$username_validation_progress, &$password_validation_progress) {
//This function returns 1 upon successful registration, 2 upon mysql query failure, and 3 upon invalid username/password
//If 1, also registers the user in the database.
//$username_validation_progress and $password_validation_progress are invalid username/password error codes
//import the sql connection
global $mysqli;
//since the username and password will be printed out on screen, sanitize the data
$username = sanitize_data($username);
$password = sanitize_data($password);
$password_check = sanitize_data($password_check);
//check if username is valid
$username_validation_progress=0;
if (strlen($username)<4) $username_validation_progress=1;
else if (strlen($username)>20) $username_validation_progress=2;
else if (preg_match ('/[^a-zA-Z0-9]/', $username)) $username_validation_progress=3;
else if (is_username_taken_ma($username, $mysqli)==1) $username_validation_progress=4;
else $username_validation_progress=5;
//check if password is valid
$password_validation_progress=0;
if (strlen($password)<12) $password_validation_progress=1;
else if (strlen($password)>40) $password_validation_progress=2;
else if (preg_match ('/[^a-zA-Z0-9]/', $password)) $password_validation_progress=3;
else if ($password!=$password_check) $password_validation_progress=4;
else $password_validation_progress=5;
if (($username_validation_progress==5)&&($password_validation_progress==5)) { //if the username and password are valid, then...
$salt = hash('sha512', openssl_random_pseudo_bytes(23));
$password = hash('sha512', $password . $salt);
if ($stmt = $mysqli->prepare("INSERT INTO users (username, password, salt) VALUES (?, ?, ?)")) { //if this mysql query has successfully run, then ....
$stmt->bind_param('sss', $username, $password, $salt);
$stmt->execute();
//for testing
//printf("Errormessage: %s\n", $mysqli->error);
if ($stmt = $mysqli->prepare("INSERT INTO monsters_and_gamesycoins (username) VALUES (?)")) { //if this mysql query has successfully run, then ....
$stmt->bind_param('s', $username);
$stmt->execute();
//succesfully registered. end function. Returns 1 = successfully registered
return 1; }
else { //if the mysql query got rejected, then...
return 2; } }
else { //if the mysql query got rejected, then...
return 2; } }
else { //if the username and password were not both valid, then...
return 3; }
} //---END function definition of register
function is_username_taken_ma($username) {
//This function returns "1" if the username does have a database match
//if it's unused, returns 0
//import the sql connection
global $mysqli;
if ($stmt = $mysqli->prepare("SELECT username FROM users WHERE username = ? LIMIT 1 ")) { //if this mysql query has successfully run, then ....
$stmt->bind_param('s', $username); //binds $username to parameter
$stmt->execute(); //executes the prepared query.
$stmt->store_result();
//$stmt->bind_result($cookie_from_the_database); //binds the result to "$cookie_from_the_database"
//$stmt->fetch();
if ($stmt->num_rows == 1) { //if the username has a match, then there will be 1 row result
return "1"; }
else { //if the username doesn't have a match, then...
return "0"; } }
else { //if the mysql query got rejected, then...
return "2"; }
} //---END function definition of is_username_taken_ma
function record_authentication_attempt($username, $result, $reason) {
//The following function records into the database successful and failed login_check attempts from sessions and cookies.
//The first parameter it takes is a string of the username.
//The second parameter it takes is a string "success" or "failure" as to the result of the login. Not using a boolean value, to make database easy to read without documentation.
//The third parameter it takes is a string message as to the reason why the login_check has failed or succeeded, for example, "cookie in browser doesn't match cookie in database".
//The fourth parameter is takes is a database connection.
//--note: about the toggling between the logging of cookie/session authentication attempts and logging of actual username/password login attempts.
//honestly, it's only really important, to detect session hijacking (the user being stupid and letting a middleman have at it),
//and to detect brute force guesses at the cookie (which should be impossible because i made the damn thing 128 bits long. it would take 700,000,000,000,000 years)
//import the sql connection
global $mysqli;
$user_ip_address = $_SERVER['REMOTE_ADDR']; // Gets the user's IP address.
$now = time(); //Gets timestamp of current time.
if (FALSE||(
$reason !='authenticated from a session variable' &&
$reason !='session variable authentication failure - login_check isnt equal to login_string' &&
$reason !='session variable authentication failure - sql query didnt return 1 row' &&
$reason !='session variable authentication failure - sql prepared statement didnt return true' &&
$reason !='session variable authentication failure - session variables not set' &&
$reason !='cookie on computer matches cookie in database upon login_check' &&
$reason !='cookie authentication failure - cookie on computer doesnt match cookie in database'
)) {
//The contents of the above if-clause STOP authentication attempts from being logged into the database and allow ONLY login attempts to be recorded.
//Toggle FALSE/TRUE at the beginning. FALSE to true to turn OFF logging of authentication attempts. TRUE to turn it ON for testing.
//YOU CAN TURN IT ON FOR 5 MINUTES TO GET A HUGE INFLUX OF DATA ON AUTHENTICATION ATTEMPTS FROM LEGITIMATE USERS AND ALSO HACKER ATTEMPTS, AND THEN TURN IT BACK OFF.
//THERE WILL BE A DATABASE ENTRY MADE FOR EVERY AUTHENTICATION ATTEMPT ON EVERY PAGE RELOAD BY EVERY IP ADDRESS.
//This data can be useful for analysis or further improvement of security and application development.
if ($stmt = $mysqli->prepare("INSERT INTO login_attempts (time, username, ip_address, result, reason) VALUES (?, ?, ?, ?, ?) ")) {
$stmt->bind_param('sssss', $now, $username, $user_ip_address, $result, $reason); //Bind the variables to the query parameters.
$stmt->execute(); }
//else { echo 'The mysql query got screwed.'; } //this line is commented out because a echo statement is unnecessary except for testing purposes and would cause html header to initialize
}
} //---END function definition of record_authentication_attempt
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment