As the title, I ask this question because the only way I know how to check if a user is logged in, is by having on top of each file a session and a query to data base to compared the sessions value.
I have something like this function, then I call this function on top of every php file, this works fine. However I dont think big website such as facebook, youtube and so on has this approach, also this means that all my files have to be .php I cant have .html as I wouldn't be able to run the function below.
public function isSessionValid()
{
session_start();
$dbConfig = new dbconfig("users");
$dbUser = $dbConfig->getDbUser();
$getUser = new GetUser($dbUser);
$result = $getUser->getUser($_SESSION['UN'],$_SESSION['PW'] );
if(!count($result) > 0){
header("Location: ../index.html");
}
}
My question is what are other efficient ways of checking for users credentials?
You don't want to have something like:
$_SESSION['PW']
Plain text unencrypted passwords are a serious concern. You could do something where upon login, you create a access token that is a random hashed string and that gets saved to the users cookies.
Here's an example:
function login()
{
$userName = 'billy';
$password = 'foobar';
// get your user data using username and password.
$userObject = new User();
$userId = $userObject->id;
// create our secure hash.
$accessToken = password_hash($password, PASSWORD_DEFAULT);
// update the user in the row.
mysqli_query($link, "UPDATE users set access_token='$accessToken' WHERE id = $userId");
// expires in 1 day, auto logout.
setcookie('userAccessToken', $accessToken, time() + 86400);
}
function getUser() {
return mysqli_query($link, "SELECT * from users WHERE access_token = ".$_COOKIE['userAccessToken']);
}
Now you only need to check for one attribute which is the access token, and its stored in the cookies in case they come back. Using the hash approach prevents anyone sniffing the cookies and getting private information.
For code maintainability you don't want duplicate code and should always try to create small reusable components that can be used across all your pages. Make a PHP file called auth.php and then just require it in the pages where you need it.
// UserPage.php
require_once __DIR__.'/lib/auth.php';
$user = getUser();
// MessagePage.php
require_once __DIR__.'/lib/auth.php';
$user = getUser();
// lib/auth.php
function getUser() {
return mysqli_query($link, "SELECT * from users WHERE access_token = ".$_COOKIE['userAccessToken']);
}
As a side note, rather than writing your application in plain php and building your own framework, I recommend you checkout laravel.com. They have video tutorials and the framework solves a lot of common problems developers run into, including this one.
One solution would be to configure the webserver to automatically route all requests through isSessionValid() first, then to their actual destination.
Related
I am building a login form using ajax php and MySql.
I've done my fair share of research and I didn't like much posts found online, so I've built the below code.
My question is, is this secure at all? I'm not using any hashing and I'm not sure how it would be done with ajax. All the examples are much appreciated
INDEX.PHP
<script>
$(document).ready(function(){
$('form[name=loginForm]').submit(function() {
$.post('ajax.php', { username: $('[name=username]').val(),
password: $('[name=password]').val()},
function(data){
if(data.success){
alert('welcome');
}else{
alert("incorrect");
}
}, 'json');
return false;
});
});
</script>
ajax.php
<?php
if($_POST){
/** Fetch data from mysql **/
$u = $_POST['username'];
$p = $_POST['password'];
$sql = "SELECT * FROM users WHERE username='$u' AND password='$p' ";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$_SESSION['userid'] = $row["username"];
$_SESSION['userid'] = $row["username"];
$data['success'] = true;
}
}
else
{
$data['success'] = false;
}
/** Fetch data from mysql **/
echo json_encode($data);
} ?>
THANKS ALOT
My question is, is this secure at all?
No, it is not secure.
I'm not using any hashing and I'm not sure how it would be done with ajax.
Authentication actually cannot be done with ajax. With respect, you're barking up the wrong tree.
Start by reading this part of the PHP manual. http://php.net/manual/en/faq.passwords.php Go read it now. We'll wait.
Welcome back. You should never put your plain text password into a database. If you're not sure why that's true read about the "Ashley Madison data breach" online or go visit https://haveIBeenPwned.com/
You want to make it as hard as possible for a cybercriminal who steals your user table to guess your users' passwords. If you store them as text, they are trivial to guess.
Let's say your users are registered already. The point of your password authentication is to
gather the username and password from the user.
look up the user by name in your database, pulling back the hashed password.
compare the hashed password in your database with the one you gathered from the user. php's password_verify() function does this well.
if the validation fails, refuse the user's information. Do not give them any hint what was wrong. Simply tell them "your login failed." You don't want to tell them "you gave the right username but the wrong password."
if the validation succeeds, you then generate a session for that user so they can continue to use other pages in your web app without logging in again. Read about php sessions here.
you use a session id to represent the session. A session id is a hard-to-guess data token with a limited lifetime. php offers a session_create_id() method for this.
you put that session id in a cookie and feed it back to your browser. You can't reliably feed cookies to browsers with AJAX so your authentication strategy won't work.
Subsequent requests to your web app present the session id in the cookie. You check it to make sure it it's valid and it hasn't timed out. Then you do what the user asks you to do.
I'm trying to create a link that when clicked will login a user automatically and take them to a specific page.
I've thought about creating some sort of hashed string that contains the user's ID, username and a few other pieces of info. When clicked these pieces of information are looked up in the DB and if validated I login them in and redirect them to a specific page.
For sites like Twitter and Facebook when I receive an email notification and click the link in my email I'm automatically taken to my inbox on the corresponding site. I'm trying to duplicate that behavior...
Are there any security issues with doing something like this or is there a safer more preferred way?
if you want to offer this feature to your users, you have to take care of two things:
The validity of the created url must be set in time (ex: 24hours, 48hours).
The created url must only work for one specific user.
(optionnal) The created url only work for one page
I propose this kind of solution to create an url which match these criteria (it's only a proof of concept):
<?php
$privateKey = 'somethingVerySecret';
$userName = 'cedric';
$url = 'my/personal/url';
$timeLimit = new DateTime('Tomorow');
function createToken($privateKey, $url, $userName, $timeLimit){
return hash('sha256', $privateKey.$url.$userName.$timeLimit);
}
function createUrl($privateKey, $url, $userName, $timeLimit){
$hash = createToken($privateKey, $url, $userName, $timeLimit->getTimestamp());
$autoLoginUrl = http_build_query(array(
'name' => $userName,
'timeLimit' => $timeLimit,
'token' => $hash
));
return $url.'?'.$autoLoginUrl;
}
function checkUrl($privateKey){
if((int)$_GET['timeLimit'] > time() ){
return false;
}
//check the user credentials (he exists, he have right on this page)
$hash = createToken($privateKey, $_SERVER['PHP_SELF'], $_GET['name'], $_GET['timeLimit']);
return ($_GET['token'] == $hash);
}
The general standard for logging in is when a user creates an account your program should create a string of seemly random letters and numbers with a certain php function in php 5.5, and then store this in a file with some sort of pointer based on the username. Then when a user tries to login you use that same function and compare the two strings. The function being hash_pbkdf2 even though this php function supports sha... encryptions do not use those. I salt the hash code with the username. Here is an article on all website login and password things. The most secure thing you can do with your website to prevent people from brute force cracking your passwords is to limit the connection speed after a couple wrong password attempt to something so slow it would take longer than the life of the universe to crack after a couple password attempts. If you wanted to make a sort of remember me button store the username in cookies But never the password the browser will take care of the remembering password part if you label your form elements correctly.
I need to create a system plugin (no auth plugin!) where a user which logges into the frontend automaticaly gets logged in the backend too.
(The user has the rights to log into the backend via /administrator.)
I try to do it via the very basic code you see below, the result is positive, but if i go to the backend the user still needs to log in.
In the session table the backend session row is set, but the "guest" field is set to 1 instead of 0 and the userid is set to 0 instead of the correct id.
How can this be done?
function onAfterInitialise() {
if(JFactory::getUser()->get('id')) { // logged in?
$credentials = array();
$credentials['username'] = "walter"; // hardcoded first
$credentials['password'] = "123"; // hardcoded first
$options = array();
$options['action'] = 'core.login.admin';
$result = $app->login($credentials, $options); // this seams to work
if (!($result instanceof Exception)) {
$app->redirect("www.bummer.de");
}
}
Apart from this being a very bad idea, as mentioned in this question Joomla! is implemented as two applications a front-end (/index.php) and back-end application (/administrator/index.php).
In the code provided you don't show where $app is initialised so I'm guessing that it's probably something like $app->JFactory::getApplication('site');.
To login to the admin app you need to get it rather than the front-end client app e.g.
$adminApp->JFactory::getApplication('administrator');
$result = $adminApp->login($credentials, $options);
n.b. this is untested code just typed in to stack overflow... it should be right.
I heard the best method to share session across multiple domains on same server is to use custom php session handler. (ie, domain name different like abc.com, xyz.com but single application.)
But after i tried it, even custom php session handler that using SAME DATABASE ON 1 SERVER can't share session, when i tried to read cookie value from different domain.
Here's my custom session handler, Please kindly check or fix if something missing here. because i've tried it for a week now. can't get it to work
P.S. To get previous session id, i use link such as: newdomain.com/?ssid=[SESSION_ID]
SESSION_INCLUDE.PHP
<?php
// config
$m_host = "localhost"; //MySQL Host
$m_user = "db_user"; //MySQL User
$m_pass = "db_pass"; //MySQL Pass
$m_db = "db_name"; //MySQL Database
$table = "sess_data";
$session_expire = 600; // Session expire time, in seconds (minutes * 60 = seconds)
$gc_probability = 100; // Probability that the garbage collection function will be called. 50% chance by default
ini_set("session.gc_probability",$gc_probability);
/* Open function; Opens/starts session
Opens a connection to the database and stays open until specifically closed
This function is called first and with each page load */
function open ($s,$n) // do not modify function parameters
{
global $session_connection, $m_host, $m_user, $m_pass, $m_db;
$session_connection = mysql_pconnect($m_host,$m_user,$m_pass);
mysql_select_db($m_db,$session_connection);
return true;
}
/* Read function; downloads data from repository to current session
Queries the mysql database, unencrypts data, and returns it.
This function is called after 'open' with each page load. */
function read ($id) // do not modify function parameters
{
global $session_connection,$session_read,$table;
$query = "SELECT data FROM `$table` WHERE id=\"{$id}\"";
$res = mysql_query($query,$session_connection);
if(mysql_num_rows($res) != 1) return ""; // must return string, not 'false'
else
{
$session_read = mysql_fetch_assoc($res);
$session_read["data"] = base64_decode($session_read["data"]);
return $session_read["data"];
}
}
function write ($id,$data) // do not modify function parameters
{
if(!$data) { return false; }
global $session_connection, $session_read, $session_expire, $table;
$expire = time() + $session_expire;
$data = mysql_real_escape_string(base64_encode($data));
if($session_read) $query = "UPDATE `$table` SET data=\"{$data}\", expire=\"{$expire}\" WHERE id=\"{$id}\"";
else $query = "INSERT INTO sess_data SET id=\"{$id}\", data=\"{$data}\", expire=\"{$expire}\"";
mysql_query($query,$session_connection);
return true;
}
function close ()
{
global $session_connection;
mysql_close($session_connection);
return true;
}
function destroy ($id) // do not modify function parameters
{
global $session_connection,$table;
$query = "DELETE FROM `$table` WHERE id=\"{$id}\"";
mysql_query($query,$session_connection);
return true;
}
function gc ($expire)
{
global $session_connection,$table;
$query = "DELETE FROM `$table` WHERE expire < ".time();
mysql_query($query,$session_connection);
}
// Set custom handlers
session_set_save_handler ("open", "close", "read", "write", "destroy", "gc");
// Start session
session_start();
?>
MySQL Database Description
create table sess_data (
id2 int not null auto_increment,
id text not null,
data text,
expire int not null,
primary key(id2)
);
You can't read cookies from one domain in another domain. That's a security thing implemented in the browser. Using a database for sessions allows you to have multiple servers share sessions on the same domain, but does not allow for multiple domains on the same server to share sessions.
If you want to share sessions between domains, you would need to implement some sort of session transfer method when you switch domains. The simplest way to do this would involve passing the session id as a GET parameter from a page on one domain to a page on the other. Then, on the other domain, you would pick up the session id and create a new session using that ID.
While that is a simple way to do it, it isn't very secure and allows for session hijacking. A better way would be to use the database to create a record with the session id in it, set a short timeout on it, and pass the ID of that record to the other domain. The other domain would then pick up the record from the database and create a session with it. If the record in the database is past it's expiration, it wouldn't pick up the session. This would provide better protection against session hijacking.
This is the purpose of session_name(). Assign a different name to each application's session to avoid collisions between $_SESSION keys. The name will be used as the session cookie's name so although both session cookies will be passed to both applications, only the one matching the application's session_name() will be used to populate $_SESSION.
// App 1
session_name('app1');
session_start();
// App 2
session_name('app2');
session_start();
You really should look into SSO (single sign-on). One option for SSO is to use OpenID (as used on SO), and using it will make your life a lot easier.
Here's an article on it : http://devzone.zend.com/article/3581
the cookies and their visibility is a problem. The browser accessing the new site would not send the session id of the old site to the server.
I think your read() does not use the ssid parameter you provide as session id but as the browser has no session with this domain the system generates one with new id as $id. Have a look if $_REQUEST['ssid'] exist in the database.
Custom session handler might a bit big for this job. You could just check if $_REQUEST['ssid'] exist in the session database and rewrite $_SESSION with it.
I was wondering if anyone could give some suggestions on my method for sharing sessions between domains on same server (same cookie storage folder).
In each pages HEAD tag on all my sites, I call the following PHP code
if(!isset($_SESSION['sso'])) {
require_once('database.php');
$sites = array('http://site1', 'http://site2');
session_regenerate_id(); //Make new session id that will be shared
$session_id = session_id();
foreach($sites as $site) {
if($site != CURRENT_SITE) {
$sesh_key = md5(SALT.$site.$session_id);
$database->insertSessionId($sesh_key, $session_id);
$url = sprintf('%s/sso_set.php?k=%s', $site, $sesh_key);
echo('<link type="text/css" rel="stylesheet" href="'.$url.'" />');
}
}
$_SESSION['sso'] = 'SET';
}
Then on each site I have a file called 'sso_set.php' which contains
<?php
session_start();
if(!isset($_SESSION['sso'])) {
require_once('database.php');
$key = $_GET['k'];
$session_id = $database->getSessionId($key);
if($session_id) {
session_destroy();
session_id($session_id);
session_start();
$database->deleteSessionId($key);
$_SESSION['sso'] = 'SET';
}
}
Is using a text/css link a good idea?
I figured this is always called even if Javascript or Images are disabled?
This code basically makes the first site out of all my sites that gets opened by the user sets the Session ID, and then passes it on to the other sites.
Seems to work pretty well.
You get a slight delay the very first time any of the sites opened and the ID is passed to the sites. But, you could do this via AJAX so the page loads fast. But, then you rely on Javascript being enabled.
Thoughts?
Need some help with how to handle sessions. I am using ajax techniques to implement a group discussion platform and alot of its success depends on whether or not i can handle sessions properly, be able to see who is online etc. How can i do this efficiently. Remember, this is a typical single url ajax application where the server only responds to request. All of the form validation is done on the client side as the user enters his data. I need help with this. Below what have written so far.
<?php
include_once "../database/dbconnect.php";
session_start();
$username = isset($_POST["userNameLogin"]) ? $_POST["userNameLogin"] : $_SESSION["userNameLogin"];
$pwd = isset($_POST["passwordLogin"]) ? $_POST["passwordLogin"] : $_SESSION["passwordLogin"];
// Sending these messages to my client side validation code json-style.
if(!isset($username)){
echo("{message : 'NoName'}");
}
elseif(!isset($pwd)){
echo("{message : 'NoPW'}");
}
// creating the session variables to hold username and pwd
$_SESSION['userNameLogin'] = $username;
$_SESSION['passwordLogin'] = $pwd;
// calling the function incuded above to make connection to mysql db
dbConnection();
//query retrieves username and pwd from db and counts the result. if it is one, then they //certianly exist and if not unset the variables created above. The varibles were created
//above so i do not have to check if they exist before unsetting them.
$sQuery = "SELECT * FROM users WHERE
username = '$username' AND password = '$pwd'";
$result = mysql_query($sQuery) or die(mysql_error());
$intFound = mysql_num_rows($result);
if ($intFound == 0) {
unset($_SESSION['userNameLogin']);
unset($_SESSION['passwordLogin']);
// AD - Access Denied
echo("{message : 'AD'}");
}
else{
//a flag to set in the database who is currently online. value of 1 for users who are //online and zero for users who are not. If i want a list of those online, i check the //column called online and then check to see if the $_SESSION['username'] exist. If it //does then i know the user is online. That is what the second script is for. New to this //stuff, and do not know a better way of doing it
mysql_query("UPDATE users SET online = '1' WHERE username = '$username'") or die(mysql_error);
}
The above script should let the user login or deny access by sending messages to the validation code on client side.
As you can see, i am new to this stuff i having my share of problems. What can i do to make sure that sessions are set and unset properly i.e when user logs out.
secondly how can i monitor who is online and who is not using sessions. This is how i am trying to check who is currently online and then building a json file with the user names and sending it to the client. Json is easier to parse.
The script below tries to determine who is online
<?php
// this script determines which sessions are currently active by
// 1.) checking to see which online fields in the users table are set to 1
// 2.) by determining if a session variable has been set for these users.
// If it is not set, it means user is no longer active and script sets its online field in the users table to zero.
// After doing this, the script, then queries the users table for online fields with values one, writes them to an
// array and passes them to the client.
include_once "../database/dbconnect.php";
//include "../validation/accessControl.php";
$tempActiveUsers = array();
$activeUsers = array();
$nonActiveUsers = array();
dbConnection();
$sql = "SELECT username from users WHERE online = '1' ";
$active_result = mysql_query($sql) or die(mysql_error);
if($active_result){
while($aValues = mysql_fetch_array($active_result)){
array_push($tempActiveUsers, $aValues['username']);
}
}
forEach($tempActiveUsers as $value){
/*if($_SESSION['$value'] == $value){
$activeUsers += $value;
} */
if(isset($_SESSION['userNameLogin']) == $value){
array_push($activeUsers, $value);
}else{
array_push($nonActiveUsers, $value);
}
}
forEach($nonActiveUsers as $value1){
$sql1 = "UPDATE users SET online='0' WHERE username = '$value1'";
$set_result = mysql_query($sql1) or die(mysql_error);
}
$length = sizeof($activeUsers);
$len = 1;
$json ='{"users" : {';
$json .= '"user":[';
forEach($activeUsers as $value2){
$json .= '{';
$json .= '"username" : "' .$value2.'" }';
if($len != $length){
$json .= ',';
}
$len++;
}
$json .= ']';
$json .= '}}';
echo $json;
Please look through and give some advice. Will appreciate that very much. My project framework is up and good, but i can implement much user functionality yet because i cann't track who is online and how to manage thier sessions. If you need more background info let me know. Thanks in advance
Add 'Log out' button and click event handler on it which makes an ajax request to server to stop session by unsetting session vars or destroying session completely, and on ajax completion callback put a function to update user interface to show user is logged out.
Log in procedure can be done as follows: user clicks 'Log in' button and some form asking for user name and password appears. Then submit this form with ajax to a server script like your first one. Server script checks whether user name and password are valid and returns authentication information to a client via callback: failure notice upon failed login or some information about user currently logged in, e.g. user name, fullname and anything you might need about this user on client side in js. Then your client script proceeds according to login status returned from server-side script.
You should always remember about security.
Before sending any sensitive data to a client side with json, you shoud always check if session is valid and started. Client-side scripts could be easily modified and executed without your control and you should prevent undesired activity only on server side.
You should apply some escaping on user-POSTed fields before using them in sql queries to avoid sql injection attacks, e.g. by using mysql_escape_string().
And instead of building json strings, you can use json_encode() which works good for primitives, objects and arrays, you'll save some time.