Authentication System : Basic Design

Being a system administrator, it is our main concern to protect users' data from theft and corruption. Regarding theft, we focus in building a sophisticated but secure authentication system which can fulfill all the basic needs we discussed in the last article. In the previous 2 articles, we learned about authentication and authorization. Also we understood the complications in building a secure system which can prevent tresspassing. But we have not code anything yet to build something. So in this article we will be designing an authentication system which will provide the functionalities we want and which will help us understand how the tech giants like google have taken security to another level. We will be writing code in php but the same applies to other languages also.

What we'll be using

Lets see what are the languages we will be using and database plus some extra libraries

Languages PHP, Javascript, HTML, CSS
Database MySQL
Libraries & Frameworks (optional) Fingerprintjs, jquery, bootstrap, validatejs

If you dont have php and mysql in your system then you should install them first before writing the code. You can download xampp.

Blueprint

Now lets see the database schema and the strategy we will use to build our system.

  • User (id [integer], email [varchar], password [varchar])
  • Session (session_id [varchar], token [varchar], user_id [integer] , expire_time [datetime])

Our system will authenticate the user based on the token stored in his machine and will prevent intrusuions.

  1. To prevent sniffing, the application should be using SSL which encrypts the data sent over network between the client and the server. But we can still do a lot to protect our system even if some man in the middle steals our data.
  2. Create the database tables according to the schema described above.
  3. When user visits a page, check for the `session_id` and `login` cookie. Two cases are possible
  4. Case #1 : If cookies are not present, ask for user credentials.
  5. Search for those credentials in the `User` table.
  6. If the credentials are correct then generate 2 random strings. One being the `session_id` and other being the `token`.
  7. Create a new entry in the `Session` table with the values (session_id, token, user_id, expire_time). The `expire_time` can be any time you wish to allow a session being idle. For example: expire_time = current_time + 24 hours.
  8. Send the session_id and token along with the response as `session_id` and `login` cookies respectively.
  9. Case #2:If `session_id` cookie is present, search for the `session_id` in the database table.
  10. If match is not found or the session has expired, ask for user credentials.
  11. If session is found and active, match the `login` cookie value with the matched session `token`.
  12. If match is not found, report a theft and delete all session data related to that user.
  13. If match is found then authenticate the user and update the token value to some other random string.
  14. Increase the expire time with 24 hours plus current system time.
  15. Send the newly generated token along with the response and update the `login` cookie.
  16. Make sure the cookies you save are set to be HTTP only so that XSS attacks can be prevented.

Now lets assume that someone steals the cookies while they were being sent to the server. Now he is able to impersonate the user But if he makes some request to the server with the stolen data then the access token will be changed and when the user tries to visit some page a theft is reported because the user has invalidated token and the user and theif both gets logged out of the system. So far so good.

But the problem arises when the theft occurs during the last request of the user. Now the user has left the application without logging out and some malicious person has the user's last authentication token. Now he is fully capabale of using the system for as long as he wants. We will see what can we do to prevent this and also how can we implement "remember me" functionality in our system. But before that lets build a system with the above strategy in mind.

Building the System

The system we will be designing is a pretty basic one but i will tell you what more you can add to take it to next level. Below are the components of the system with outlined code. The whole source code can be viewed on github fetch-info-auth repository

HTML login form : (A simple form with e-mail and password field only)

<form action="http://fetchinfo.com/fetch-info-auth/public/html/login.php" method="post">

<input type="text" name="email" maxlength="30" placeholder="username">
<input type="password" name="password" maxlength="30" placeholder="password">
<input type="submit" value="Submit">
</form>

Main Authentication Script

This script first calls another script to check whether the user has an authenticated cookie or not. If cookie is not verified then it checks whether the user has supplied his credentials or not. If credentials are provided then it verifies them and sends appropriate data.

    function auth(){

$result = authCookie() ;
if(is_integer($result)){
if(isset($_POST['email'])){
$email = $_POST['email'] ;
$pass = $_POST['password'] ;
$conn = connect() ;
$query = "Select * from user where email='".$email."' and password='".$pass."'" ;
$result = mysqli_query($conn, $query) ;
if(mysqli_num_rows($result)==1){

$uid = mysqli_fetch_row($result)[0] ;
$new_token = generateRandomString(100) ;
$new_time = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s'))+86400) ;
$new_session = generateRandomString(100) ;


$query = "insert into session values('".$new_session."','".$new_token."',".$uid.",'".$new_time."')" ;

if( mysqli_query($conn, $query)){
return [$new_session, $new_token] ;
}
return globals("UNAUTHENTICATED") ;
}
return globals("UNAUTHENTICATED") ;
}
return globals("UNAUTHENTICATED") ;
}
else{
return $result ;
}
}

Cookie Authentication Script

This script checks whether a user has authenticated cookie or not. If the verification succeeds then it generates a new token and returns the new token which is returned by the main authentication script and the html pages override the existing cookie with the new generated token.

 function authCookie(){

$conn = connect() ;
if(isset($_COOKIE['session_id'])){
$session_id = $_COOKIE['session_id'] ;
$query = "select * from session where session_id='".$session_id."'" ;
$result = mysqli_query($conn, $query) ;
if(mysqli_num_rows($result) == 1){
$token = mysqli_fetch_row($result)[1] ;
if(isset($_COOKIE['login'])){
$login = $_COOKIE['login'] ;
echo "Session: ".$session_id."<br/> Token: ".$token."<br/> Cookie: ".$login ;
if($token == $login){
$new_token = generateRandomString(100) ;
$new_time = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s'))+86400000) ;
$query = "update session set token='".$new_token."', expire_time='".$new_time."' where session_id='".$session_id."'" ;
$result = mysqli_query($conn, $query) ;
return [$session_id, $new_token] ;
}
else{
return globals("THEFT") ;
}
}
else{
return globals("UNAUTHENTICATED") ;
}
}
return globals("UNAUTHENTICATED") ;
}
return globals("UNAUTHENTICATED") ;
}

A successful verification of either the cookie or the credentials lands the user to the home page which only contains a hello message in this case. For convinience, the session_id cookie and the token cookie values are displayed on each page so that you can see what is happening. Each refresh to the home page updates the token as well. There are many other scripts as well. So if you want to see the whole source code, you can visit the github fetch-info-auth repository

.

Running the System

Now lets see how can we quick run our system so that we can understand things more clearly. Here i am making some assumptions which are :

  1. You have apache installed
  2. You have mysql installed
  3. You have php installed
  4. You have created the database according to the schema discussed above.
All things settled down, now clone the repository from github and configure the apache localhost to view pages from this cloned repository. Also changed the connection settings in repository/script/auth/connect.php to point to your mysql database. If all goes accordingly then you will be able to see the login.php page. To do the login, you will have to create an account i.e. to add a user in the user table according to the schema we discussed above. Just create the account and do the required login and you will be redirected to the home page where you will have the option to logout.

Please note that this system currently does not erase the session data on detecting theft. There are also other loop holes which you can cover in the methods by changing the response based on the flags sent by the authentication functions. Also note that the code assumes that the database schema is exactly what is defined above. I will try to generalise the code in the future.

Additional Care

We have just created a basic system which only provides the required functionalities but does not fully protect the system. There are a couple of things we can do increase the security.

  • Use encryption over your application by using SSL protocol to prevent session hijacking.
  • Limit the number of login attempts to prevent dictionary attacks.
  • In case of persistent login ("remember me") option, different approach is required.
  • Use scripts to prevent SQL injection attacks.
  • Make your cookies to be read by http only to prevent cross-site scripting attacks.

I hope you learned something new here. In case you found some incorrect information or you think it can be improved then do share your thoughts in the comments. If you have any query then you can drop it in comments and i will try to resolve it.


Comments

Popular posts from this blog

Authentication: A step to security

Understanding Python Decorators