Reputation: 1046
I'm building a web app that has a chat feature. I'm using Laravel 5.4 for the backend and Angular 4 for the front-end.
Everything is working (meaning I can broadcast and recieve) but I'm not at all sure how to secure it. The chat will always be 1 to 1 so its private and has to be secure. Each chat room will have a unique id but somebody could still listen in.
Currently I'm using JWTs for authentication when I make requests from my frontend to my API, but I'm not sure if its possible to implement something similar for this. I know I can pass the token from the frontend using the query
option but than I'm unsure how to parse it and I'm also unsure how to verify that it indeed belongs to the user that is trying to access the chat (should I make a request to the API to verify in server.js
? That doesn't seem efficient. Is it good enough to compare the user id of the token to the user id that will be passed in the data?)
If anybody has any advice or knows a better way to do it, it would be greatly apperciated
Event that is fired off from Laravel when a new message is posted
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $data;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
$this->data = array(
'message'=> 'hi'
);
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('chat');
}
}
server.js (node.js)
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.psubscribe('private-chat', function(err, count) {
console.log('psubscribe');
});
redis.on('pmessage', function(subscribed, channel, message) {
console.log('pmessage', subscribed, channel, message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
Frontend component
socket: io.Socket;
this.socket = io.connect("http://webapp.test:3000", { query: this.token });
this.socket.on("private-chat:App\\Events\\NewMessage", (data) =>
{
console.log("Data", data);
});
Upvotes: 0
Views: 673
Reputation: 7420
Try to use SSL (confidentiality)
SSL as we know ensures that the server you're communicating with is actually the webservice you want.
Authentication (To avoid certificate pinning)
You need authentication
in your case you are using JWT
with HS256
, I would strongly recommend you to use RS256 algorythm JWT
in this case with private and public keys.
It doesn't matter that nobody else can listen to the conversation between the two of you if you don't know for sure who's on the other end (authentication).
Since I would build the app in the way that if session authentication
between two channels its not set then never unfold the content of the data that is being send.
Unique session
As slong as your sevice is authenticated using JWT
you send them back an authentication token
. This is as simple as a random number or a GUID
. This identifier will be required as part of any request to send or receive data on this channel during this session, it will only be accepted on this particular channel, and only as long as this unique session is open.
One more security check: link reply attack
I gave you the tips that I use everyday to seccurely send data back and forth with central banks (so following those tips I think your app should be pretty secure)
UPDATE
How to handle JWT
Create a new middleware Verify JWT token
since the middleware in laravel its outter layer of core vendor that means if authentication fails it fails in outter layer not in core.
Group the routes under Verify JWT token
middleware!
Create a RedisRepository
this could be under App\RedisRepository
. This class should be responsible for fetching data from redis.
On middleware decrypt user JWT get the decrypted payload(this might be user UUID or ID).
Fetch user ID
from RedisRepository compare with the decrypted payload if positive authentication passes otherwise abort 403 unauthenticated!
Upvotes: 1