0

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);
});
derrickrozay
  • 1,048
  • 3
  • 15
  • 37
  • currious to know what kind of encryption for JWT ? I think SSL will solve all your concerns about sending data to a server and securing it in transit. – Leo Dec 19 '17 at 21:40
  • I'm using the `tymon-jwt` library for laravel which uses `HS256` by default. I will be using SSL in the future but wont anybody be able to guess the channel name and be able to access the broadcast channel? Thats what worries me – derrickrozay Dec 19 '17 at 21:45

1 Answers1

1

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!

Leo
  • 7,274
  • 5
  • 26
  • 48
  • Thanks this is really helpful. So what you are saying in unique session is that first authenticate using JWT and than generate a random GUID and store that on the frontend and backend and check it every time a message is broadcast and on disconnect destroy it? How do you intercept the JWT using Redis and verify it? – derrickrozay Dec 19 '17 at 22:28
  • Hopefully you are familiar with Laravel. I use a middleware that comes with `tymon-jwt` to check for a token and validate it on every API route. On the frontend the `token` is stored and sent with every request – derrickrozay Dec 19 '17 at 22:41
  • 1
    @derrickrozay no worry very familiar with it! Check updated answer! Not sure what to help more, unless I sit and I implement it :p – Leo Dec 19 '17 at 23:01