Monday, May 14, 2018

Cross-site Request Forgery protection in web applications via Synchronizer Token Patterns

What is CSRF(Cross-site Request Forgery)?

Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. Little bit confusing right, watch the below video you will understand it fully.



What is Synchronizer Token Patterns? 

Synchronizer token pattern (STP) is a technique where a token, secret and unique value for each request, is embedded by the web application in all HTML forms and verified on the server side. The token may be generated by any method that ensures unpredictability and uniqueness.

Let's implement this using a simple example using PHP.

First, create a basic html form to login users. with Username field and password field.

<form action="login.php" method="POST" class="ajax" >
    <lable>Username:</lable>
    <input type="text" required name="uname" />
    <lable>Username:</lable>
    <input type="password" required name="password" />
     
    <input type="submit" value="Login"/>
<div id="success"></div>
</form

Then we need to create a cookie called "s_id" (later will use this to validate our form)  from php session which generates a unique value when you visit the website and once you close browser it will destroy the session.


<?php 
session_start();
$s_id = session_id();
setcookie("s_id",$s_id,time()+(1440),"/","localhost",false,true);
?>


Now the cookie is created in the browser, now we can generate a synchronizer token pattern simply a unique value for each request.


<?php 
    
       if (empty($_SESSION['token'])) {
       
            $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
      
        $token = $_SESSION['token'];
        
   }


In here I have used "bin2hex and openssl_random_pseudo_bytes" because "openssl_random_pseudo_bytes" is cryptographically secure and bin2hex convert binary data into hexadecimal representation. So that the token value will be unique each time.

Now we need to pass token value as POST method to login verification page. In order to do that we should assign the token into hidden field in the form as below.


<input type="hidden" name="csr" value="<?php echo $_SESSION['token']; ?>">


Finally, let's implement the login page with a ajax with jquery. We will be using a function that automatically gets values from the form and the action url and submits it using ajax as below.


<script>
 $('form.ajax').on('submit', function() {
    var that = $(this),
            url = that.attr('action'),
            type = that.attr('method'),
            data = {};
    that.find('[name]').each(function(index, value) {
        var that = $(this),
                name = that.attr('name'),
                value = that.val();
        data[name] = value;
    });
    $.ajax({
        url: url,
        type: type,
        data: data,
        success: function(response) {
            $("#success").append("<h3 style='color:red; font-size:15px;'>" + response + "</h3>");          
             
        }
    });
    return false;
});
 
 </script>

Login.php


<?php 
session_start();
$uname=$_POST['uname'];
$password=$_POST['password'];
$userSession=$_COOKIE['s_id'];
$csr=$_POST['csr'];
if(empty($uname) || empty($password)){
    echo "Please fill all the required fields\n";
}else{
    
    if($uname="admin" && $password="admin" && $userSession=session_id() && $csr=$_SESSION['token']){
        echo "Login successful, Hello admin";
    }else{
        echo "Login un-successful";
    }
}
?>

Download source code : https://github.com/theekshanasl/SSS/tree/master/Assignment%201









Cross-site Request Forgery protection in web applications via Double Submit Cookies Patterns

What is Double submit cookies?

A double submit cookie is defined as sending a random value in both a cookie and as a request parameter, with the server verifying if the cookie value and request value match.

Simply what it means is setting a cookie with a generated token in server side so that attacker cannot generate a valid token.

Let's implement this, first follow the steps in this article https://theekshanasl.blogspot.com/2018/05/cross-site-request-forgery-protection_14.html

then set a cookie when the token is generated as below.


<?php 
session_start();
$s_id = session_id();
if (empty($_SESSION['token'])) {
    $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
    $token = $_SESSION['token'];

    setcookie("csr_token", $token, time() + (440), "/", "localhost", false, true);
}
setcookie("s_id", $s_id, time() + (1440), "/", "localhost", false, true);
?>

and finally, change login.php file to get the cookie value "csr_token" to a variable and check in the if condition like below.



<?php 
session_start();
$uname=$_POST['uname'];
$password=$_POST['password'];
$userSession=$_COOKIE['s_id'];
$user_token=$_COOKIE['csr_token'];
$csr=$_POST['csr'];
if(empty($uname) || empty($password)){
    echo "Please fill all the required fields\n";
}else{
    
    if($uname="admin" && $password="admin" && $userSession=session_id() && $csr=$_SESSION['token'] && $csr=$user_token){
        echo "Login successful, Hello admin";
    }else{
        echo "Login un-successful";
    }
}
?>

Complete source code: https://github.com/theekshanasl/SSS/tree/master/Assignment%202

OAuth with Facebook Javascript SDK

What is OAuth?

OAuth (Open Authorization) is an open standard for token-based authentication and authorization on the Internet. ... OAuth acts as an intermediary on behalf of the end user, providing the service with an access token that authorizes specific account information to be shared. Like login to websites or services using Facebook, Google, etc.

In this article, we are going to implement Facebook login using Javascript SDK.

First, you need to create a Facebook app, in order to do that follow steps in https://developers.facebook.com/docs/apps/register/#create-app

Facebook does not allow non-ssl SDK access. So either you need to generate a self-signed SSL certificate or get one from a certificate authority (CA). I'll be using Google Chrome throughout this tutorial, In Google Chrome, sites that are using un-trusted certificate are not allowed to be accessed. Type chrome://flags/ in the address bar and search for "Allow invalid certificates for resources loaded from localhost." enable it.

Now create a html file called index.html and generate a login button from https://developers.facebook.com/docs/facebook-login/web/login-button



<html>
<header>
    <title>FBLogin</title>


</header>

<body>

<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = 'https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v3.0&appId=YOURAPPID&autoLogAppEvents=1';
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

<div class="fb-login-button" data-max-rows="1" data-size="large" data-button-type="continue_with" data-show-faces="false" data-auto-logout-link="false" data-use-continue-as="false"></div>
</body>

</html>




Because of the scadles happen in the past and the recent one to Facebook users now only be able to get the Name, Email, Profile Picture by default. Refere to the commented code below.



<script>
        window.fbAsyncInit = function () {
            FB.init({
                appId: '1123043511168814',
                autoLogAppEvents: true,
                xfbml: true,
                version: 'v3.0'
            });
            FB.getLoginStatus(function (response) {
                statusChangeCallback(response);
            });
            function checkLoginState() {
                FB.getLoginStatus(function (response) {
                    statusChangeCallback(response);
                });
            }
        };
        (function (d, s, id) {
            var js, fjs = d.getElementsByTagName(s)[0];
            if (d.getElementById(id)) { return; }
            js = d.createElement(s); js.id = id;
            js.src = "https://connect.facebook.net/en_US/sdk.js";
            fjs.parentNode.insertBefore(js, fjs);
        }(document, 'script', 'facebook-jssdk'));
        
        //Check if the user is already connected to the app.
        function statusChangeCallback(response) {
            if (response.status === 'connected') {
                console.log('Logged in');
                FBAPI();
                setElements(true);
                
                
            } else {
                setElements(false);
                console.log('Not logged in');
            }
        }
        
        //get Facebook profile information 
        function FBAPI() {
            FB.api('me?fields=id,name,email', function (response) {
                if (response && !response.error) {
                    console.log(response);
                    //Passing the json object 
                    showprofile(response);
                }
            })
           
        }
        //Show elements according to the login status
         function setElements(isLoggedIn) {
                if (isLoggedIn) {
                    document.getElementById('profile').style.display='block';
                    document.getElementById('fbbtn').style.display='none';
                    document.getElementById('logout').style.display='block';
                } else {
                    document.getElementById('profile').style.display='none';
                    document.getElementById('fbbtn').style.display='block';
                    document.getElementById('logout').style.display='none';
                }
            }
        //This will show the profile details using html
            function showprofile(user){
              let profile=`
              <br />
              <img src="http://graph.facebook.com/${user.id}/picture?type=large" />
                <h3 class="my-4">${user.name}</h3>
                <h4>User ID: ${user.id}</h4>
                
                <h4>User E mail: ${user.email}</h4>
                
              `
              document.getElementById('profile').innerHTML=profile;
            }
            function logout(){
                FB.logout(function(response){
                    setElements(false);
                });
            }
            //You need to get a reviewed facebook app with user post permission to work.
            var body = 'Hello, This is a post from SSS_TEST app';
            FB.api('/me/feed', 'post', { message: body }, function (response) {
                if (!response || response.error) {
                    alert('Error occured');
                } else {
                    alert('Post ID: ' + response.id);
                }
            });
        
    </script>

Comple source code : https://github.com/theekshanasl/SSS/tree/master/Assignemnt%203