Websocket chat, get session data from apache












0












$begingroup$


In my chat system users are allowed to report spammers, I'm using the Rachet Websocket library from http://socketo.me/docs/hello-world, I was searching for a way to use the $_SESSION variables from Apache server on Websocket server, the only way (easy way) i found was put the data from the $_SESSION variables in the websocket url connection:



//this is on the Apache server
var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);


This way i can identify users and check if he are flagged as spammer, and also retrive infomation fom my table to use in the chat (user name, avatar...etc) But only this is not enough because he could put this code bellow on the developer tools and send menssages to everyone as he wish:



var conn = new WebSocket('ws://localhost:8080');
data = {msg: 'hello'};
conn.send(JSON.stringify(data));


To prevent it i also added a password on the query string to send to the websocket server.



Because the connection to the websocket is in javascript i had to do some workaround, I'm sure that there's a better way to do it, example: i saw on the Ratchet website that i can use the Symfony Library to use sessions http://socketo.me/docs/sessions, but it seems to be much complicated, i have never used this library, and to learn how to use it would be really tiring.



register_account.php:



//code used to generate the user's tokens, i know that it does
//not generate a unique token, but i have a sql query to check if
//the generated token already exist in my table, if exist i do a
//redirect to a error page, it's not the best way but was the bestest
//that i found
$a_uniq_token = md5(mt_rand(10, 1000000000));
$b_uniq_token = md5(mt_rand(10, 1000000000));

$a_l_hidden_token = md5(mt_rand(10, 1000000000));
$a_r_hidden_token = md5(mt_rand(10, 1000000000));
$b_l_hidden_token = md5(mt_rand(10, 1000000000));
$b_r_hidden_token = md5(mt_rand(10, 1000000000));


index.php:



//in this ajax i get my password and the unique token that
//is used to identify the user
$.ajax({
type:'post',
url:siteURL+'/check_user.php',
success:function(data){
var jsonKey = JSON.parse(data);
var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);
.
.
.
}
})


check_user.php:



if(!isset($_SESSION))session_start();
if($_SERVER['REQUEST_METHOD'] != 'POST' || empty($_SESSION['user_id'])){
session_unset();
session_destroy();
die();
}

//this function might be kinda usless because i have a password
//but i would like to keep it

//I used two more tokens to hide the real token, i made it
//because since only me knows the token length, it will be
//really hard to guess the token from another user, and it's
//to confuse his mind because he would probably think that it's a
//72 token length
//My first idea was to use bin2hex(random_bytes(150)), but
//i failed to find a way to use this hex token in a SELECT query
//I'm not sure about this one bellow but I think it's safe atleast
function hideToken($hidden_left, $hidden_right, $real_token){
$a = substr($hidden_left,0,15);
$b = substr($hidden_right,0,25);
$c = $real_token;
return base64_encode($a.$c.$b);
}

$a_l = $_SESSION['a_l_hidden_token'];
$a_r = $_SESSION['a_r_hidden_token'];
$c_a = $_SESSION['a_uniq_token'];

$b_l = $_SESSION['b_l_hidden_token'];
$b_r = $_SESSION['b_r_hidden_token'];
$c_b = $_SESSION['b_uniq_token'];

$token_a = hideToken($a_l, $a_r, $c_a);
$token_b = hideToken($b_l, $b_r, $c_b);

require 'websocket_password.php';
//here i used password_hash() to encrypt my password and send through
//the query string, and because a string encrypted with password_hash()
//can't be decrypt it's perfect for my case
$token_passw_crypt = password_hash($token_passw, PASSWORD_BCRYPT);
$crypt = base64_encode($token_passw_crypt);

echo json_encode(['key_1' => $token_a, 'key_2' => $token_b, 'key_3' => $crypt]);


websocket_password.php:



//obviously it's not my real password, just a example
$token_passw = 'h41j55@5G1.@/2hU>$5F1hm1.$#d5g2Blh#0g.vw;we/#55wch74jtwdw';


websocket_chat.php:



namespace MyApp;
require dirname(__DIR__) . '/vendor/autoload.php';
use RatchetMessageComponentInterface;
use RatchetConnectionInterface;

function userData($a_uniq_token, $b_uniq_token, $token_crypt, $msg = NULL){

require dirname(__DIR__).'/websocket_password.php';
//check the password, and if it returns false he
//won't be able to connect and send menssages to another user
if(password_verify($token_passw, base64_decode($token_crypt))){

//extract the tokens from the query string
$a_token_decode = substr(base64_decode($a_uniq_token), 15);
$b_token_decode = substr(base64_decode($b_uniq_token), 15);
$a_token = substr($a_token_decode, 0, 32);
$b_token = substr($b_token_decode, 0, 32);

require dirname(__DIR__).'/data_base_config.php';

$get_data = $conn_db->prepare("SELECT `linkN`, `username`, `avatarUP` FROM `users` WHERE `a_uniq_token` = :a_uniq_token AND `b_uniq_token` = :b_uniq_token");
$get_data->bindParam(":a_uniq_token", $a_token, PDO::PARAM_STR);
$get_data->bindParam(":b_uniq_token", $b_token, PDO::PARAM_STR);
$get_data->execute();
$data = $get_data->fetch(PDO::FETCH_ASSOC);

//check if the user is flagged as spammer
$linkN = $data['linkN'];
if(!empty($linkN)){
$abuso_verbal = 5;
$spam = 5;
$check_report = $conn_db->prepare("SELECT count(link_id) FROM `report_public_chat` WHERE `link_id` = :link_id AND (`abuso_verbal` > :abuso_verbal OR `spam` > :spam)");
$check_report->bindParam(":link_id", $linkN, PDO::PARAM_INT);
$check_report->bindParam(":abuso_verbal", $abuso_verbal, PDO::PARAM_INT);
$check_report->bindParam(":spam", $spam, PDO::PARAM_INT);
$check_report->execute();
$rst_report = $check_report->fetchColumn();

if($rst_report == 0){
if(!empty($msg)){
try{
$msg_data = json_decode($msg);
$msgPC = $msg_data->msgPC ?? NULL;
$imgShare = $msg_data->imgShare ?? NULL;
$ytUrl = $msg_data->ytUrl ?? NULL;

$data = '{//json here, to send the message data}';

//if everything is right, retrun the $data
//else, return 1 and he won't be able to do
//anything
return $data;
}catch (Exception $e){
return 1;
}
}else{
//return 0 because the variable $msg will be
//empty when i use this function to allow the
//conection to the webscoket in the function
//onOpen()
return 0;
}
}else{
return 1;
}
}else{
//return 1 if everything is right unless the user token,
//it can happen because i could have deleted the user's
//account while he is online (for some reason), and it
//will return 1 till he reloads the page and be redirected
//to the login page
return 1;
}
}else{
return 1;
}
}
//these functions bellow is from http://socketo.me/docs/hello-world,
public function onOpen(ConnectionInterface $conn) {

parse_str($conn->httpRequest->getUri()->getQuery(), $token);
$key_a = $token['key_1'];
$key_b = $token['key_2'];
$psswd = $token['key_3'];

//check if the query strings is not empty and if the function
//userData() anything that is != 1
if(!empty($key_a) && !empty($key_b) && !empty($psswd)){
if(userData($key_a, $key_b, $psswd) != 1){
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})n";
}
}

}
//because this function onMessage() is triggered on every message
//he does not need to reload the page to be "blocked" from the chat
public function onMessage(ConnectionInterface $conn, $msg) {

parse_str($conn->httpRequest->getUri()->getQuery(), $token);
$key_a = $token['key_1'];
$key_b = $token['key_2'];
$psswd = $token['key_3'];

if(!empty($key_a) && !empty($key_b) && !empty($psswd)){

$get_data = userData($key_a, $key_b, $psswd, $msg);

//if userData() returns anything that is != 1 he is allowed to
//send messages
if($get_data != 1){
foreach ($this->clients as $client) {
$client->send($get_data);
}
}else{
//if userData() returnn 1, remove the user from the current
//conections, this way he cannot receive messages
$this->clients->detach($conn);
}
}

}


I made some tests and this code is working perfectly, but i would like to know where i can improve it, and if there's any erros, because if someone find a way to bypass it, it will be hard for me to fix it because at my actual knowlegde i'm not seeing any breachs in this code.









share









$endgroup$

















    0












    $begingroup$


    In my chat system users are allowed to report spammers, I'm using the Rachet Websocket library from http://socketo.me/docs/hello-world, I was searching for a way to use the $_SESSION variables from Apache server on Websocket server, the only way (easy way) i found was put the data from the $_SESSION variables in the websocket url connection:



    //this is on the Apache server
    var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);


    This way i can identify users and check if he are flagged as spammer, and also retrive infomation fom my table to use in the chat (user name, avatar...etc) But only this is not enough because he could put this code bellow on the developer tools and send menssages to everyone as he wish:



    var conn = new WebSocket('ws://localhost:8080');
    data = {msg: 'hello'};
    conn.send(JSON.stringify(data));


    To prevent it i also added a password on the query string to send to the websocket server.



    Because the connection to the websocket is in javascript i had to do some workaround, I'm sure that there's a better way to do it, example: i saw on the Ratchet website that i can use the Symfony Library to use sessions http://socketo.me/docs/sessions, but it seems to be much complicated, i have never used this library, and to learn how to use it would be really tiring.



    register_account.php:



    //code used to generate the user's tokens, i know that it does
    //not generate a unique token, but i have a sql query to check if
    //the generated token already exist in my table, if exist i do a
    //redirect to a error page, it's not the best way but was the bestest
    //that i found
    $a_uniq_token = md5(mt_rand(10, 1000000000));
    $b_uniq_token = md5(mt_rand(10, 1000000000));

    $a_l_hidden_token = md5(mt_rand(10, 1000000000));
    $a_r_hidden_token = md5(mt_rand(10, 1000000000));
    $b_l_hidden_token = md5(mt_rand(10, 1000000000));
    $b_r_hidden_token = md5(mt_rand(10, 1000000000));


    index.php:



    //in this ajax i get my password and the unique token that
    //is used to identify the user
    $.ajax({
    type:'post',
    url:siteURL+'/check_user.php',
    success:function(data){
    var jsonKey = JSON.parse(data);
    var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);
    .
    .
    .
    }
    })


    check_user.php:



    if(!isset($_SESSION))session_start();
    if($_SERVER['REQUEST_METHOD'] != 'POST' || empty($_SESSION['user_id'])){
    session_unset();
    session_destroy();
    die();
    }

    //this function might be kinda usless because i have a password
    //but i would like to keep it

    //I used two more tokens to hide the real token, i made it
    //because since only me knows the token length, it will be
    //really hard to guess the token from another user, and it's
    //to confuse his mind because he would probably think that it's a
    //72 token length
    //My first idea was to use bin2hex(random_bytes(150)), but
    //i failed to find a way to use this hex token in a SELECT query
    //I'm not sure about this one bellow but I think it's safe atleast
    function hideToken($hidden_left, $hidden_right, $real_token){
    $a = substr($hidden_left,0,15);
    $b = substr($hidden_right,0,25);
    $c = $real_token;
    return base64_encode($a.$c.$b);
    }

    $a_l = $_SESSION['a_l_hidden_token'];
    $a_r = $_SESSION['a_r_hidden_token'];
    $c_a = $_SESSION['a_uniq_token'];

    $b_l = $_SESSION['b_l_hidden_token'];
    $b_r = $_SESSION['b_r_hidden_token'];
    $c_b = $_SESSION['b_uniq_token'];

    $token_a = hideToken($a_l, $a_r, $c_a);
    $token_b = hideToken($b_l, $b_r, $c_b);

    require 'websocket_password.php';
    //here i used password_hash() to encrypt my password and send through
    //the query string, and because a string encrypted with password_hash()
    //can't be decrypt it's perfect for my case
    $token_passw_crypt = password_hash($token_passw, PASSWORD_BCRYPT);
    $crypt = base64_encode($token_passw_crypt);

    echo json_encode(['key_1' => $token_a, 'key_2' => $token_b, 'key_3' => $crypt]);


    websocket_password.php:



    //obviously it's not my real password, just a example
    $token_passw = 'h41j55@5G1.@/2hU>$5F1hm1.$#d5g2Blh#0g.vw;we/#55wch74jtwdw';


    websocket_chat.php:



    namespace MyApp;
    require dirname(__DIR__) . '/vendor/autoload.php';
    use RatchetMessageComponentInterface;
    use RatchetConnectionInterface;

    function userData($a_uniq_token, $b_uniq_token, $token_crypt, $msg = NULL){

    require dirname(__DIR__).'/websocket_password.php';
    //check the password, and if it returns false he
    //won't be able to connect and send menssages to another user
    if(password_verify($token_passw, base64_decode($token_crypt))){

    //extract the tokens from the query string
    $a_token_decode = substr(base64_decode($a_uniq_token), 15);
    $b_token_decode = substr(base64_decode($b_uniq_token), 15);
    $a_token = substr($a_token_decode, 0, 32);
    $b_token = substr($b_token_decode, 0, 32);

    require dirname(__DIR__).'/data_base_config.php';

    $get_data = $conn_db->prepare("SELECT `linkN`, `username`, `avatarUP` FROM `users` WHERE `a_uniq_token` = :a_uniq_token AND `b_uniq_token` = :b_uniq_token");
    $get_data->bindParam(":a_uniq_token", $a_token, PDO::PARAM_STR);
    $get_data->bindParam(":b_uniq_token", $b_token, PDO::PARAM_STR);
    $get_data->execute();
    $data = $get_data->fetch(PDO::FETCH_ASSOC);

    //check if the user is flagged as spammer
    $linkN = $data['linkN'];
    if(!empty($linkN)){
    $abuso_verbal = 5;
    $spam = 5;
    $check_report = $conn_db->prepare("SELECT count(link_id) FROM `report_public_chat` WHERE `link_id` = :link_id AND (`abuso_verbal` > :abuso_verbal OR `spam` > :spam)");
    $check_report->bindParam(":link_id", $linkN, PDO::PARAM_INT);
    $check_report->bindParam(":abuso_verbal", $abuso_verbal, PDO::PARAM_INT);
    $check_report->bindParam(":spam", $spam, PDO::PARAM_INT);
    $check_report->execute();
    $rst_report = $check_report->fetchColumn();

    if($rst_report == 0){
    if(!empty($msg)){
    try{
    $msg_data = json_decode($msg);
    $msgPC = $msg_data->msgPC ?? NULL;
    $imgShare = $msg_data->imgShare ?? NULL;
    $ytUrl = $msg_data->ytUrl ?? NULL;

    $data = '{//json here, to send the message data}';

    //if everything is right, retrun the $data
    //else, return 1 and he won't be able to do
    //anything
    return $data;
    }catch (Exception $e){
    return 1;
    }
    }else{
    //return 0 because the variable $msg will be
    //empty when i use this function to allow the
    //conection to the webscoket in the function
    //onOpen()
    return 0;
    }
    }else{
    return 1;
    }
    }else{
    //return 1 if everything is right unless the user token,
    //it can happen because i could have deleted the user's
    //account while he is online (for some reason), and it
    //will return 1 till he reloads the page and be redirected
    //to the login page
    return 1;
    }
    }else{
    return 1;
    }
    }
    //these functions bellow is from http://socketo.me/docs/hello-world,
    public function onOpen(ConnectionInterface $conn) {

    parse_str($conn->httpRequest->getUri()->getQuery(), $token);
    $key_a = $token['key_1'];
    $key_b = $token['key_2'];
    $psswd = $token['key_3'];

    //check if the query strings is not empty and if the function
    //userData() anything that is != 1
    if(!empty($key_a) && !empty($key_b) && !empty($psswd)){
    if(userData($key_a, $key_b, $psswd) != 1){
    $this->clients->attach($conn);
    echo "New connection! ({$conn->resourceId})n";
    }
    }

    }
    //because this function onMessage() is triggered on every message
    //he does not need to reload the page to be "blocked" from the chat
    public function onMessage(ConnectionInterface $conn, $msg) {

    parse_str($conn->httpRequest->getUri()->getQuery(), $token);
    $key_a = $token['key_1'];
    $key_b = $token['key_2'];
    $psswd = $token['key_3'];

    if(!empty($key_a) && !empty($key_b) && !empty($psswd)){

    $get_data = userData($key_a, $key_b, $psswd, $msg);

    //if userData() returns anything that is != 1 he is allowed to
    //send messages
    if($get_data != 1){
    foreach ($this->clients as $client) {
    $client->send($get_data);
    }
    }else{
    //if userData() returnn 1, remove the user from the current
    //conections, this way he cannot receive messages
    $this->clients->detach($conn);
    }
    }

    }


    I made some tests and this code is working perfectly, but i would like to know where i can improve it, and if there's any erros, because if someone find a way to bypass it, it will be hard for me to fix it because at my actual knowlegde i'm not seeing any breachs in this code.









    share









    $endgroup$















      0












      0








      0





      $begingroup$


      In my chat system users are allowed to report spammers, I'm using the Rachet Websocket library from http://socketo.me/docs/hello-world, I was searching for a way to use the $_SESSION variables from Apache server on Websocket server, the only way (easy way) i found was put the data from the $_SESSION variables in the websocket url connection:



      //this is on the Apache server
      var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);


      This way i can identify users and check if he are flagged as spammer, and also retrive infomation fom my table to use in the chat (user name, avatar...etc) But only this is not enough because he could put this code bellow on the developer tools and send menssages to everyone as he wish:



      var conn = new WebSocket('ws://localhost:8080');
      data = {msg: 'hello'};
      conn.send(JSON.stringify(data));


      To prevent it i also added a password on the query string to send to the websocket server.



      Because the connection to the websocket is in javascript i had to do some workaround, I'm sure that there's a better way to do it, example: i saw on the Ratchet website that i can use the Symfony Library to use sessions http://socketo.me/docs/sessions, but it seems to be much complicated, i have never used this library, and to learn how to use it would be really tiring.



      register_account.php:



      //code used to generate the user's tokens, i know that it does
      //not generate a unique token, but i have a sql query to check if
      //the generated token already exist in my table, if exist i do a
      //redirect to a error page, it's not the best way but was the bestest
      //that i found
      $a_uniq_token = md5(mt_rand(10, 1000000000));
      $b_uniq_token = md5(mt_rand(10, 1000000000));

      $a_l_hidden_token = md5(mt_rand(10, 1000000000));
      $a_r_hidden_token = md5(mt_rand(10, 1000000000));
      $b_l_hidden_token = md5(mt_rand(10, 1000000000));
      $b_r_hidden_token = md5(mt_rand(10, 1000000000));


      index.php:



      //in this ajax i get my password and the unique token that
      //is used to identify the user
      $.ajax({
      type:'post',
      url:siteURL+'/check_user.php',
      success:function(data){
      var jsonKey = JSON.parse(data);
      var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);
      .
      .
      .
      }
      })


      check_user.php:



      if(!isset($_SESSION))session_start();
      if($_SERVER['REQUEST_METHOD'] != 'POST' || empty($_SESSION['user_id'])){
      session_unset();
      session_destroy();
      die();
      }

      //this function might be kinda usless because i have a password
      //but i would like to keep it

      //I used two more tokens to hide the real token, i made it
      //because since only me knows the token length, it will be
      //really hard to guess the token from another user, and it's
      //to confuse his mind because he would probably think that it's a
      //72 token length
      //My first idea was to use bin2hex(random_bytes(150)), but
      //i failed to find a way to use this hex token in a SELECT query
      //I'm not sure about this one bellow but I think it's safe atleast
      function hideToken($hidden_left, $hidden_right, $real_token){
      $a = substr($hidden_left,0,15);
      $b = substr($hidden_right,0,25);
      $c = $real_token;
      return base64_encode($a.$c.$b);
      }

      $a_l = $_SESSION['a_l_hidden_token'];
      $a_r = $_SESSION['a_r_hidden_token'];
      $c_a = $_SESSION['a_uniq_token'];

      $b_l = $_SESSION['b_l_hidden_token'];
      $b_r = $_SESSION['b_r_hidden_token'];
      $c_b = $_SESSION['b_uniq_token'];

      $token_a = hideToken($a_l, $a_r, $c_a);
      $token_b = hideToken($b_l, $b_r, $c_b);

      require 'websocket_password.php';
      //here i used password_hash() to encrypt my password and send through
      //the query string, and because a string encrypted with password_hash()
      //can't be decrypt it's perfect for my case
      $token_passw_crypt = password_hash($token_passw, PASSWORD_BCRYPT);
      $crypt = base64_encode($token_passw_crypt);

      echo json_encode(['key_1' => $token_a, 'key_2' => $token_b, 'key_3' => $crypt]);


      websocket_password.php:



      //obviously it's not my real password, just a example
      $token_passw = 'h41j55@5G1.@/2hU>$5F1hm1.$#d5g2Blh#0g.vw;we/#55wch74jtwdw';


      websocket_chat.php:



      namespace MyApp;
      require dirname(__DIR__) . '/vendor/autoload.php';
      use RatchetMessageComponentInterface;
      use RatchetConnectionInterface;

      function userData($a_uniq_token, $b_uniq_token, $token_crypt, $msg = NULL){

      require dirname(__DIR__).'/websocket_password.php';
      //check the password, and if it returns false he
      //won't be able to connect and send menssages to another user
      if(password_verify($token_passw, base64_decode($token_crypt))){

      //extract the tokens from the query string
      $a_token_decode = substr(base64_decode($a_uniq_token), 15);
      $b_token_decode = substr(base64_decode($b_uniq_token), 15);
      $a_token = substr($a_token_decode, 0, 32);
      $b_token = substr($b_token_decode, 0, 32);

      require dirname(__DIR__).'/data_base_config.php';

      $get_data = $conn_db->prepare("SELECT `linkN`, `username`, `avatarUP` FROM `users` WHERE `a_uniq_token` = :a_uniq_token AND `b_uniq_token` = :b_uniq_token");
      $get_data->bindParam(":a_uniq_token", $a_token, PDO::PARAM_STR);
      $get_data->bindParam(":b_uniq_token", $b_token, PDO::PARAM_STR);
      $get_data->execute();
      $data = $get_data->fetch(PDO::FETCH_ASSOC);

      //check if the user is flagged as spammer
      $linkN = $data['linkN'];
      if(!empty($linkN)){
      $abuso_verbal = 5;
      $spam = 5;
      $check_report = $conn_db->prepare("SELECT count(link_id) FROM `report_public_chat` WHERE `link_id` = :link_id AND (`abuso_verbal` > :abuso_verbal OR `spam` > :spam)");
      $check_report->bindParam(":link_id", $linkN, PDO::PARAM_INT);
      $check_report->bindParam(":abuso_verbal", $abuso_verbal, PDO::PARAM_INT);
      $check_report->bindParam(":spam", $spam, PDO::PARAM_INT);
      $check_report->execute();
      $rst_report = $check_report->fetchColumn();

      if($rst_report == 0){
      if(!empty($msg)){
      try{
      $msg_data = json_decode($msg);
      $msgPC = $msg_data->msgPC ?? NULL;
      $imgShare = $msg_data->imgShare ?? NULL;
      $ytUrl = $msg_data->ytUrl ?? NULL;

      $data = '{//json here, to send the message data}';

      //if everything is right, retrun the $data
      //else, return 1 and he won't be able to do
      //anything
      return $data;
      }catch (Exception $e){
      return 1;
      }
      }else{
      //return 0 because the variable $msg will be
      //empty when i use this function to allow the
      //conection to the webscoket in the function
      //onOpen()
      return 0;
      }
      }else{
      return 1;
      }
      }else{
      //return 1 if everything is right unless the user token,
      //it can happen because i could have deleted the user's
      //account while he is online (for some reason), and it
      //will return 1 till he reloads the page and be redirected
      //to the login page
      return 1;
      }
      }else{
      return 1;
      }
      }
      //these functions bellow is from http://socketo.me/docs/hello-world,
      public function onOpen(ConnectionInterface $conn) {

      parse_str($conn->httpRequest->getUri()->getQuery(), $token);
      $key_a = $token['key_1'];
      $key_b = $token['key_2'];
      $psswd = $token['key_3'];

      //check if the query strings is not empty and if the function
      //userData() anything that is != 1
      if(!empty($key_a) && !empty($key_b) && !empty($psswd)){
      if(userData($key_a, $key_b, $psswd) != 1){
      $this->clients->attach($conn);
      echo "New connection! ({$conn->resourceId})n";
      }
      }

      }
      //because this function onMessage() is triggered on every message
      //he does not need to reload the page to be "blocked" from the chat
      public function onMessage(ConnectionInterface $conn, $msg) {

      parse_str($conn->httpRequest->getUri()->getQuery(), $token);
      $key_a = $token['key_1'];
      $key_b = $token['key_2'];
      $psswd = $token['key_3'];

      if(!empty($key_a) && !empty($key_b) && !empty($psswd)){

      $get_data = userData($key_a, $key_b, $psswd, $msg);

      //if userData() returns anything that is != 1 he is allowed to
      //send messages
      if($get_data != 1){
      foreach ($this->clients as $client) {
      $client->send($get_data);
      }
      }else{
      //if userData() returnn 1, remove the user from the current
      //conections, this way he cannot receive messages
      $this->clients->detach($conn);
      }
      }

      }


      I made some tests and this code is working perfectly, but i would like to know where i can improve it, and if there's any erros, because if someone find a way to bypass it, it will be hard for me to fix it because at my actual knowlegde i'm not seeing any breachs in this code.









      share









      $endgroup$




      In my chat system users are allowed to report spammers, I'm using the Rachet Websocket library from http://socketo.me/docs/hello-world, I was searching for a way to use the $_SESSION variables from Apache server on Websocket server, the only way (easy way) i found was put the data from the $_SESSION variables in the websocket url connection:



      //this is on the Apache server
      var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);


      This way i can identify users and check if he are flagged as spammer, and also retrive infomation fom my table to use in the chat (user name, avatar...etc) But only this is not enough because he could put this code bellow on the developer tools and send menssages to everyone as he wish:



      var conn = new WebSocket('ws://localhost:8080');
      data = {msg: 'hello'};
      conn.send(JSON.stringify(data));


      To prevent it i also added a password on the query string to send to the websocket server.



      Because the connection to the websocket is in javascript i had to do some workaround, I'm sure that there's a better way to do it, example: i saw on the Ratchet website that i can use the Symfony Library to use sessions http://socketo.me/docs/sessions, but it seems to be much complicated, i have never used this library, and to learn how to use it would be really tiring.



      register_account.php:



      //code used to generate the user's tokens, i know that it does
      //not generate a unique token, but i have a sql query to check if
      //the generated token already exist in my table, if exist i do a
      //redirect to a error page, it's not the best way but was the bestest
      //that i found
      $a_uniq_token = md5(mt_rand(10, 1000000000));
      $b_uniq_token = md5(mt_rand(10, 1000000000));

      $a_l_hidden_token = md5(mt_rand(10, 1000000000));
      $a_r_hidden_token = md5(mt_rand(10, 1000000000));
      $b_l_hidden_token = md5(mt_rand(10, 1000000000));
      $b_r_hidden_token = md5(mt_rand(10, 1000000000));


      index.php:



      //in this ajax i get my password and the unique token that
      //is used to identify the user
      $.ajax({
      type:'post',
      url:siteURL+'/check_user.php',
      success:function(data){
      var jsonKey = JSON.parse(data);
      var conn = new WebSocket('ws://localhost:8080?key_1='+jsonKey.key_1+'&key_2='+jsonKey.key_2+'&key_3='+jsonKey.key_3);
      .
      .
      .
      }
      })


      check_user.php:



      if(!isset($_SESSION))session_start();
      if($_SERVER['REQUEST_METHOD'] != 'POST' || empty($_SESSION['user_id'])){
      session_unset();
      session_destroy();
      die();
      }

      //this function might be kinda usless because i have a password
      //but i would like to keep it

      //I used two more tokens to hide the real token, i made it
      //because since only me knows the token length, it will be
      //really hard to guess the token from another user, and it's
      //to confuse his mind because he would probably think that it's a
      //72 token length
      //My first idea was to use bin2hex(random_bytes(150)), but
      //i failed to find a way to use this hex token in a SELECT query
      //I'm not sure about this one bellow but I think it's safe atleast
      function hideToken($hidden_left, $hidden_right, $real_token){
      $a = substr($hidden_left,0,15);
      $b = substr($hidden_right,0,25);
      $c = $real_token;
      return base64_encode($a.$c.$b);
      }

      $a_l = $_SESSION['a_l_hidden_token'];
      $a_r = $_SESSION['a_r_hidden_token'];
      $c_a = $_SESSION['a_uniq_token'];

      $b_l = $_SESSION['b_l_hidden_token'];
      $b_r = $_SESSION['b_r_hidden_token'];
      $c_b = $_SESSION['b_uniq_token'];

      $token_a = hideToken($a_l, $a_r, $c_a);
      $token_b = hideToken($b_l, $b_r, $c_b);

      require 'websocket_password.php';
      //here i used password_hash() to encrypt my password and send through
      //the query string, and because a string encrypted with password_hash()
      //can't be decrypt it's perfect for my case
      $token_passw_crypt = password_hash($token_passw, PASSWORD_BCRYPT);
      $crypt = base64_encode($token_passw_crypt);

      echo json_encode(['key_1' => $token_a, 'key_2' => $token_b, 'key_3' => $crypt]);


      websocket_password.php:



      //obviously it's not my real password, just a example
      $token_passw = 'h41j55@5G1.@/2hU>$5F1hm1.$#d5g2Blh#0g.vw;we/#55wch74jtwdw';


      websocket_chat.php:



      namespace MyApp;
      require dirname(__DIR__) . '/vendor/autoload.php';
      use RatchetMessageComponentInterface;
      use RatchetConnectionInterface;

      function userData($a_uniq_token, $b_uniq_token, $token_crypt, $msg = NULL){

      require dirname(__DIR__).'/websocket_password.php';
      //check the password, and if it returns false he
      //won't be able to connect and send menssages to another user
      if(password_verify($token_passw, base64_decode($token_crypt))){

      //extract the tokens from the query string
      $a_token_decode = substr(base64_decode($a_uniq_token), 15);
      $b_token_decode = substr(base64_decode($b_uniq_token), 15);
      $a_token = substr($a_token_decode, 0, 32);
      $b_token = substr($b_token_decode, 0, 32);

      require dirname(__DIR__).'/data_base_config.php';

      $get_data = $conn_db->prepare("SELECT `linkN`, `username`, `avatarUP` FROM `users` WHERE `a_uniq_token` = :a_uniq_token AND `b_uniq_token` = :b_uniq_token");
      $get_data->bindParam(":a_uniq_token", $a_token, PDO::PARAM_STR);
      $get_data->bindParam(":b_uniq_token", $b_token, PDO::PARAM_STR);
      $get_data->execute();
      $data = $get_data->fetch(PDO::FETCH_ASSOC);

      //check if the user is flagged as spammer
      $linkN = $data['linkN'];
      if(!empty($linkN)){
      $abuso_verbal = 5;
      $spam = 5;
      $check_report = $conn_db->prepare("SELECT count(link_id) FROM `report_public_chat` WHERE `link_id` = :link_id AND (`abuso_verbal` > :abuso_verbal OR `spam` > :spam)");
      $check_report->bindParam(":link_id", $linkN, PDO::PARAM_INT);
      $check_report->bindParam(":abuso_verbal", $abuso_verbal, PDO::PARAM_INT);
      $check_report->bindParam(":spam", $spam, PDO::PARAM_INT);
      $check_report->execute();
      $rst_report = $check_report->fetchColumn();

      if($rst_report == 0){
      if(!empty($msg)){
      try{
      $msg_data = json_decode($msg);
      $msgPC = $msg_data->msgPC ?? NULL;
      $imgShare = $msg_data->imgShare ?? NULL;
      $ytUrl = $msg_data->ytUrl ?? NULL;

      $data = '{//json here, to send the message data}';

      //if everything is right, retrun the $data
      //else, return 1 and he won't be able to do
      //anything
      return $data;
      }catch (Exception $e){
      return 1;
      }
      }else{
      //return 0 because the variable $msg will be
      //empty when i use this function to allow the
      //conection to the webscoket in the function
      //onOpen()
      return 0;
      }
      }else{
      return 1;
      }
      }else{
      //return 1 if everything is right unless the user token,
      //it can happen because i could have deleted the user's
      //account while he is online (for some reason), and it
      //will return 1 till he reloads the page and be redirected
      //to the login page
      return 1;
      }
      }else{
      return 1;
      }
      }
      //these functions bellow is from http://socketo.me/docs/hello-world,
      public function onOpen(ConnectionInterface $conn) {

      parse_str($conn->httpRequest->getUri()->getQuery(), $token);
      $key_a = $token['key_1'];
      $key_b = $token['key_2'];
      $psswd = $token['key_3'];

      //check if the query strings is not empty and if the function
      //userData() anything that is != 1
      if(!empty($key_a) && !empty($key_b) && !empty($psswd)){
      if(userData($key_a, $key_b, $psswd) != 1){
      $this->clients->attach($conn);
      echo "New connection! ({$conn->resourceId})n";
      }
      }

      }
      //because this function onMessage() is triggered on every message
      //he does not need to reload the page to be "blocked" from the chat
      public function onMessage(ConnectionInterface $conn, $msg) {

      parse_str($conn->httpRequest->getUri()->getQuery(), $token);
      $key_a = $token['key_1'];
      $key_b = $token['key_2'];
      $psswd = $token['key_3'];

      if(!empty($key_a) && !empty($key_b) && !empty($psswd)){

      $get_data = userData($key_a, $key_b, $psswd, $msg);

      //if userData() returns anything that is != 1 he is allowed to
      //send messages
      if($get_data != 1){
      foreach ($this->clients as $client) {
      $client->send($get_data);
      }
      }else{
      //if userData() returnn 1, remove the user from the current
      //conections, this way he cannot receive messages
      $this->clients->detach($conn);
      }
      }

      }


      I made some tests and this code is working perfectly, but i would like to know where i can improve it, and if there's any erros, because if someone find a way to bypass it, it will be hard for me to fix it because at my actual knowlegde i'm not seeing any breachs in this code.







      php security validation authorization websocket





      share












      share










      share



      share










      asked 3 mins ago









      nobodynobody

      576




      576






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214813%2fwebsocket-chat-get-session-data-from-apache%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214813%2fwebsocket-chat-get-session-data-from-apache%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Costa Masnaga

          Fotorealismo

          Sidney Franklin