Websocket chat, get session data from apacheProtecting a database from bad dataFiltering data from usersGet...
VAT refund for a conference ticket in Sweden
Is divide-by-zero a security vulnerability?
Should we avoid writing fiction about historical events without extensive research?
Roots of 6th chords on the guitar for different inversions/voicings
I encountered my boss during an on-site interview at another company. Should I bring it up when seeing him next time?
If a set is open, does that imply that it has no boundary points?
The need of reserving one's ability in job interviews
Calculating Hyperbolic Sin faster than using a standard power series
Starting index at zero
What type of investment is best suited for a 1-year investment on a down payment?
Giving a talk in my old university, how prominently should I tell students my salary?
Is there a full canon version of Tyrion's jackass/honeycomb joke?
Source for Cremation Specifically Not Jewish
What is the difference between a forward slip and a side slip?
What is better: yes / no radio, or simple checkbox?
Real life puzzle: Unknown alphabet or shorthand
At what level can a party fight a mimic?
Dystopian novel where telepathic humans live under a dome
Did Amazon pay $0 in taxes last year?
What should the omniscient narrator call a character?
Where is the line between being obedient and getting bullied by a boss?
How can atoms be electrically neutral when there is a difference in the positions of the charges?
Can we carry rice to Japan?
Don't know what I’m looking for regarding removable HDDs?
Websocket chat, get session data from apache
Protecting a database from bad dataFiltering data from usersGet data from some SOAP resourcesReal-time bitcoin data feed and storage using websocket frameworkImmediately send redirect response, preserving session dataSimple PHP session handler class (using MySQL for session data storage)Read and display data from MySQL tableEliminate redundancy from session authenticationSend Opencv::Mat image from Qt application to HTML client, using websocketGet chat message data from table, grouped by date
$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.
php security validation authorization websocket
$endgroup$
add a comment |
$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.
php security validation authorization websocket
$endgroup$
add a comment |
$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.
php security validation authorization websocket
$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
php security validation authorization websocket
asked 6 mins ago
nobodynobody
576
576
add a comment |
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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