Wednesday, January 10, 2018

How to validate Cross-Site Request Forgery (CSRF) in php [solved]

Here is my security About Cross-Site Request Forgery (CSRF) implementation based on above guidelines. Please have a look into below code.

Check CSRF class file


class csrfCheker{  

/**
  * This function is used to check if the request matches the correct header, 
  * referer is same as domain, data is from post/ajax and checks token
  * @params array $options 
  * format as 
  $options = array( 
  'method'  => 'POST', 
  'ajax'    => true, 
  'referer' => true, 
  'origin'  => true, 
  'user'    => array('login' => true, 'type' => 'Lender'), 
  'token'   => array('check' => true, 'value' => 'token_value', 'match_with' => 'server_value') 
  )
  * @returns array( 'status' => true, 'msg' => $msg )
  *
  * @author Bikash ranjan <nayakr.bikash@gmail.com>
  * @since 9th Jan, 2018
  */

  static function validateRequests( $options = array( 'method' => 'POST', 'referer' => true ) ){
        $request_error    = true;
        $error_msg        = 'Invalid Request';
        $http_referer     = $_SERVER['HTTP_REFERER'];
        $request_method   = $_SERVER["REQUEST_METHOD"];
        $x_requested_with = $_SERVER['HTTP_X_REQUESTED_WITH'];
        $http_origin      = $_SERVER["HTTP_ORIGIN"];
        $server_name      = $_SERVER["SERVER_NAME"];
        // echo '<pre>';print_r($_SERVER); // echo '<pre>same ';var_dump($options);exit;
        
        //validate 
        if( $options['method'] == 'POST' || $options['method'] == 'GET' ){//for GET/POST method
       if ( $options['method'] == $request_method ) { 
        $request_error = false;
       } else{
        self::errorResponse( true, "Only ".$options['method']." request accepted");
       }
   } 
   if( $options['ajax'] == true ){
       if ( $x_requested_with == 'XMLHttpRequest' ) { //for ajax method
        $request_error = false;
       } else{
           self::errorResponse( true, "Only Ajax request accepted");
       }
   } 
   if( $options['referer'] === true ){ //for referer check
    $refererUrl   = parse_url( $http_referer );
            $refererUrlId = $refererUrl[ "scheme" ] . "://" . $refererUrl[ "host" ];

            if( isset($refererUrl)) {
                if( $refererUrlId != "https://".$server_name ){
                    self::errorResponse( true, "Invalid Referer");
                }else{
                $request_error = false;
                }
            } else{
            self::errorResponse( true, "Invalid Referer");
       }
   } 
   if( $options['origin'] === true ){ //for same origin check
    if ( isset($http_origin) ) {
                if ( "https://".$server_name!= $http_origin ) {
                    self::errorResponse( true, "Invalid Origin header: ".$http_origin);
                } else{
                    $request_error = false;
                }
       } else {
              $request_error = false;
           //self::errorResponse( true, "No Origin header");
       }
   } 
   if( isset($options['token']['check']) && $options['token']['check'] === true ){ //for token check
       if ( isset($options['token']['value'])) {
                if ( $options['token']['value']!= $options['token']['match_with'] ) {
                    self::errorResponse( true, "Invalid Token");
                } else{
                    $request_error = false;
                }
       } else {
           self::errorResponse( true, "No Token received");
       }
   } 
   if( isset($options['user']['login']) && $options['user']['login'] === true ){ //for user login & type check
       if ( JFactory::getUser()->id>0 ) {
                if ( isset($options['user']['type']) ) {//check here user type
                    if( self::checkUserType($options['user']['type']) ){
                    $request_error = false;
                    } else{
                    self::errorResponse( true, "Not Authorized for this resource");
                    }
                } else{
                    $request_error = false;
                }
       } else {
           self::errorResponse( true, "Not logged In");
       }
   }

        
  }

  static function errorResponse( $error, $msg=''){
if( $error === true ){
        header("HTTP/1.1 403 Access Forbidden");
        header("Content-Type: text/plain");
        exit($msg);
    }
  } 

}

Before calling any method just include these 2 line-

require_once('helpers/csrfcheker.php');
csrfCheker::validateRequests(['method' => 'POST', 'referer' => true, 'origin' => true, 'user' => ['login' => true]]); 

No comments:

Post a Comment