Socket.io-auth - hide the credentials from payload request - php

Im building my socket application with laravel broadcaasting. I made my server script and then added https like in this script: (The code may contain errors because it is written from memory)
var fs = require('fs');
var https = require('https');
var express = require('express');
var app = express();
var options = {
key: fs.readFileSync('./file.pem'),
cert: fs.readFileSync('./file.crt')
};
var serverPort = 3000;
var server = https.createServer(options, app);
var io = require('socket.io')(server);
require('socketio-auth')(io, {
authenticate: authenticate,
postAuthenticate: postAuthenticate,
disconnect: disconnect,
timeout: 1000
});
after that i added socketio-auth and modified it for just username and password authentication.
function authenticate(socket, data, callback) {
if (data.username != "username") {
return callback(new Error("User not found"));
}
return callback(null, user.password == "password");
}
}
My question is about credntials I'm sending via socket.
import VueSocketio from 'vue-socket.io';
Vue.use(VueSocketio, socketio('https://socketserver.com:1923', {secure: true}));
var vm = new Vue({
sockets:{
connect: function(){
console.log('socket connected')
this.$socket.emit('authentication', {username : "username", password: "password"});
},
},
})
Im actually using Vue with vue-socketio but its working with connection and with getting / sending information properly.
Problem I got is when Im going to console in google chrome im getting plain text socket emit authentication information like
(REQUEST PAYLOAD : {authentication: {username: "username", password : "password"}}).
Is that normal thing when Im using ssl? Something is wrong with my code?
Or I need to encrypt then decrypt this information myself?
I thought all Im sending via HTTPS is encrypted.
Looking for ur replay. Thanks!

Okey I made my own encryptor.
For client Im emiting encrypted information with data and the verify hash with socket.id.
And for server i decrypted and check hmac verification with socket.id.

Related

Encrypt with flutter and php, decrypt with php and flutter

I have a chat application created using flutter dart and php mysql as backend and also node js for socket.io
So what i want is if i send a message via flutter dart, i want to encrypt it and send to node js via socket.io which will send it to the other client's flutter app and decrypt it there for the user to see and the node.js will also send it to my php script via json format and stores it in my database via post request. Also I will soon create a website where those messages will be decryted and displayed on the user browser and when i send message using the browser i also want to encrypt it and store in the database so that both flutter and web user can see the decrypted format.
const https = require("https");
const http = require("http");
const qs = require("querystring");
function send_to_db(msg) {
console.log(msg);
var postData = qs.stringify(msg);
var options = {
hostname: "*****.com",
port: 443,
path: "/src/chats/post.php",
method: "POST",
rejectUnauthorized: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": postData.length,
},
checkServerIdentity: function (host, cert) {
return undefined;
},
};
var buffer = "";
var req = https.request(options, (res) => {
res.on("data", function (chunk) {
buffer += chunk;
});
res.on("end", function () {
console.log(buffer);
});
});
req.on("error", (e) => {
console.error(e);
});
req.write(postData);
req.end();
return buffer;
}
Right now is am only encrypting and decrypting using php and am afraid of man in the middle attack since my data can be intercepted from flutter app to node.js before reaching my php side
Please what do I do to achieve this

Private chat (PHP + Socket.io) with PHP Sessions

I am developing a website which uses a private messaging system using php + socket.io.
From the beginning i passed the sender_id, recipient_id and text to socket.io using socket.emit but later realized that this could be easily tampered with and wanted to use my php sessions in some way to be sure that the sender_id is indeed the sender_id.
I have the following setup right now but i dont really understand how to pass the session from index.php to app.js and then connect to redis-server in app.js to get the PHPSESSID which holds the user_id.
Server 1 running nginx + php-fpm (index.php)
Server 2 running node.js with socket.io (app.js)
Server 3 running redis for session management
My code right now looks like the following but is obviously missing the redis part right now which i would really appriciate some help with.
Thanks!
index.php
<?php
session_start();
if ($_SESSION['user_id'] == false){
header("Location:login.php");die;
}
?>
<script>
var socket = io('https://app01.dev.domain.com:8895');
socket.on('connect', function(){
console.log("Connected to websockets");
});
socket.on('event', function(data){});
socket.on('disconnect', function(){});
$('.chat-message').keypress(function (e) {
if (e.which == 13) {
console.log("send message");
var friend_id = $(this).attr('id');
friend_id = friend_id.split("-");
friend_id = friend_id[3];
var obj = {
recipient_id: friend_id,
text: $(this).val()
};
socket.emit('chat_message', obj);
$(this).val('');
return false;
}
});
</script>
app.js
var https = require("https"), fs = require("fs");
var options = {
key: fs.readFileSync('/etc/letsencrypt/live/domain/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/domain/cert.pem'),
ca: fs.readFileSync('/etc/letsencrypt/live/domain/chain.pem')
};
var app = https.createServer(options);
var io = require("socket.io")(app);
var redis = require("redis");
// This i want to fill with for example PHPSESSION:user_id that i get from redis and later use it as sender
// var all_clients = {};
io.set("transports", ["websocket", "polling"]);
io.on("connection", function(client){
console.log("Client connected");
// Here i would like to connect to redis in some way and get the user_id but dont really understand how
//all_clients[USER_ID_FROM_REDIS] = client.id;
//var user_id = USER_ID_FROM_REDIS;
client.on("chat_message", function(data){
var obj = {
to: data.recipient_id,
text: data.text
};
console.log("Message inbound from socket: "+client.id+" from: "+data.user_id+" to: "+data.recipient_id+" with text: "+data.text);
});
client.on("disconnect", function(){
console.log("Client disconnected ");
//delete all_clients[USER_ID_FROM_REDIS];
});
});
app.listen(8895, function(){
console.log("listening on *:8895");
});
var recursive = function () {
//console.log("Connected clients: "+Object.keys(all_clients).length);
//console.log(JSON.stringify(all_clients));
setTimeout(recursive,2000);
}
recursive();
HTTP in itself does not protect against MITM attacks, to protect against MITM the server certificate needs to be pined.
To protect against a user being spoofed you need authentication such as logging-in or a secret token like Dropbox.
Add certificate pinning, that is just jargon for validating that you are connecting to the correct server and not a MITM by verifying the certificate that is sent by the server. MITM used to be harder but WiFi has made it easy to connect to the wrong end-point at Hot Sports, even at home I have seen this.

How to store usernames from php session to socket.io library in nodejs and socket connection disconnects on page refresh.Why?

I am making a chat application for my web job portal.I used to save user's name from php session to nodejs socket io library..I am confused..it is ok to store 10k users in socket object.if yes then how to maintain that users list? Another problem is when user navigates from one page to another..socket disconnect and again connect..Does it effect my application performance or nodejs server perform?
Please guide me through tutorials or blog..I have not find relevant docs yet about socket connection management ..Thanks in advance!!
You can store your data into socket.
For example,
On Server side, use like this,
var socketIo = require('/socket.io').listen(8080);
var usernames=[];
socketIo.sockets.on('connection', function (socket) {
socket.on('storeUserData', function (data) {
var userInfo = new Object();
userInfo.userName = data.userName;
userInfo.SocketId = socket.id;
usernames.push(userInfo);
});
socket.on('disconnect', function (data) {
var len = usernames.length;
for(var i=0; i<len; i++){
var user = usernames[i];
if(user.socketId == socket.id){
usernames.splice(i,1);
break;
}
}
});
});
and on client side, you need to add this
<script>
var userName = <?php echo $_SESSION['userName'] ?>;
var socket = io.connect('http://localhost', {port: 8080});
socket.on('connect', function (data) {
socket.emit('storeUserData', { 'userName' : userName });
});
</script>
Socket connection disconnects on page refresh.Why?
It is default behaviour of socket.io.

PHP + SockJS + Redis: Unicast

My application stack:
On my server runs a Redis server. The PHP backend communicates with Predis library with the Redis server. It will publish messages. These messages will be fetched by my Redis client (node.js) and pushed to the connected websocket clients (with SockJS).
My problem:
It runs well. At least for broadcast messages. Now I came to the point I need to send a unicast message and I'm stuck... How to connect the user on the backend side (sender of messages) with the connected client of the websocket?
Code snippets:
PHP
$redis = new Client();
$redis->publish('updates', Random::getUniqueString());
Redis client on node.js server
redis.subscribe('updates');
redis.on('message', function(channel, data) {
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
sockets[id].write(data);
}
}
});
SockJS client
mySocketFactory.setHandler('message', function(event) {
console.log(event.data);
});
Like I said. Working well but the id used for the socket connection is not known by the PHP backend.
Edit: One idea I got in mind is to use cookies.
I found a way to solve my problem. When the socket connection is established I sent a request to my PHP backend and ask for the user id. This is stored on the node.js server. When messages are incoming there is a check if they are for specific user and handle them only for them.
So, what do I store exactly on my node server?
var sockets = {}; // {connection_id: socket_connection}
var connIdToUser = {}; // {connection_id: user_id}
var connIdsForUser = {}; // {user_id: [connection_id_1, connection_id_2 ,...]}
socketServer.on('connection', function(conn) {
sockets[conn.id] = conn;
var options = {
host: os.hostname(),
port: 80,
path: '/user/id',
method: 'GET'
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
var userId = JSON.parse(chunk).id;
connIdToUser[conn.id] = userId;
if (!connIdsForUser.hasOwnProperty(userId)) {
connIdsForUser[userId] = [];
}
connIdsForUser[userId].push(conn.id);
console.log('connection id ' + conn.id + ' related to user id ' + userId);
});
});
req.end();
conn.on('close', function() {
console.log('connection lost ' + conn.id);
// remove connection id from stack for user
var connections = connIdsForUser[connIdToUser[conn.id]];
var index = connections.indexOf(conn.id);
if (index > -1) {
connections.splice(index, 1);
}
// remove connection at all
delete sockets[conn.id];
// remove relation between connection id and user
delete connIdToUser[conn.id];
});
});
The reason for storing the relation between user id an connection id twice is the different use case I need either for sending a message or deleting the connection for the close event. Otherwise I would have to use a nested loop.
As you can see deleting a socket is fairly easy. Although deleting the connection from the connection stack of an user is a little bit complicated.
Let's continue with the sending of a message. Here I defined a structure of the message I get from the Redis server:
{
targets: [], // array of unit ids (can be empty)
data: <mixed> // the real data
}
Sending the data to the sockets looks like:
redis.on('message', function(channel, message) {
message = JSON.parse(message);
// unicast/multicast
if (message.targets.length > 0) {
message.targets.forEach(function(userId) {
if (connIdsForUser[userId] !== undefined) {
connIdsForUser[userId].forEach(function(connId) {
sockets[connId].write(message.data);
});
}
});
// broadcast
} else {
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
sockets[id].write(message.data);
}
}
}
});
Since I store the connection stack per user it is quite easy to send the data to all sockets related to a specific user. So what I can do now is unicast (array with one user id), multicast (array with more than one user id) and broadcast (empty array).
It's working well for my use case.

IBM Worklight - How to access JSON sent using an adapter in server-side PHP?

I am developing a hybrid application in IBM Worklight.
In my app, there is a registration form. I have a requirement: After the user registers with the app, the form data will be sent to an external server in JSON format using an HTTP adapter.
In the external server,
How to access the JSON data sent using the HTTP adapter in a PHP file? and
How to send back a response in the same JSON format?
Please give demo codes of both HTTP adapter and server side PHP code.
Client code:
function callAdapter(){
var invocationData = {
adapter : 'MyAdapter',
procedure : 'MyAdapterProcedure',
parameters : [username, password]
};
WL.Client.invokeProcedure(invocationData, {
onSuccess : adapterSuccessCallback,
onFailure : adapterFailureCallback
});
}
Adapter implementation:
function myAdapterProcedure(username, password) {
var credentials = JSON.stringify({username: username, password: password});
var input = {
method : 'post',
returnedContentType : 'json',
path : "/myPHPscript.php",
parameters: {credentials: credentials}
};
return WL.Server.invokeHttp(input);
}
PHP script:
<?php
$jsonObj = $_POST['credentials'];
$credentials = json_decode($jsonObj)
// sanitation, database calls, etc
$returnDict = array();
$returnDict["success"] = true;
echo json_encode($returnDict);
?>

Categories