These methods are currently assuming you are using the Mosquitto MQTT broker & have ssl/tls setup so wss (web sockets secure) can work. If not you can follow this link to find out how http://www.steves-internet-guide.com/mosquitto-tls/
Making a secure MQTT chat that works with web-sockets can have its issues, however, with a little bit of setup it can be a very secure method of communication, (even in the browser!)
I’m going to quickly give an overview of the potential security hole you can fall in if you are not careful, and it is very useful to know.
However, there is a way around this. Well, technically two, each with their positives and negatives. (I’m letting you know now, I personally use a mix of method 1 & method 2, so as to be the most secure both on the application level & on MQTT’s level)
Method 1 : ACL
Use ACL (Access Control List)
What ACL will allow you to do, is set specific patterns of topics to be valid for publishing or subscribing (see https://mosquitto.org/man/mosquitto-conf-5.html). In our case we want a specific topic to only be readable if the Client ID which is set on connection to the broker is part of the topic. Essentially rendering the ability to get any messages unless, your client ID matches a section of the subscribing topic, impossible. (…and because all other chat topics won’t be knowable to an attacker in advance, we can use this)
This is great because if you set up your chat infrastructure so that each chat’s user has their own randomly generated (large) Client ID (per chat), you can set up topics which include that client ID meaning only they can subscribe and see the messages.
let’s say we have two topics one for each user. “/chats/user1/messages” & “/chats/user2/messages”
So in this case user 1 will publish to “/chats/user2/messages” and user 2 publishes to “/chats/user1/messages” and each user subscribes to their own topic.
Now, this is important that user2 subscribing to “/chats/user2/messages” has the client ID of “user2” for the next step to work properly.
So how do we do this? If you have not already set this up you can do it with the following commands on the terminal (Ubuntu)
touch /etc/mosquitto/aclfile nano /etc/mosquitto/aclfile
In that file, we can set up some rules. For our above example, the rule we want is this..
pattern read /chats/%c/messages
%c is essentially a filter to check if the current client id is the same as the subscribing topic in that specific location.
Save the file, Restart the mosquitto broker (usually “sudo systemctl start mosquitto”) and *ALL* users connected to the broker will have to follow this rule, meaning if you set the client IDs to a large randomly generated string, much like a UUID and use that in the topic where %c is located, you can be certain no-one can guess or brute force that random string and so no one can connect and intercept the message.
This rule also stops wildcards, which is our main aim. we don’t want ANYONE other than the client themselves knowing what messages are going through that topic. so even if you subscribed to /chats/# you would not get any messages from anyone! (so long as your client ID was different)
Method 2: Encryption
This is a relatively simple security method, for any messages being sent through MQTT we encrypt it before sending and decrypt it once received
//ENCRYPT var message_crypt = CryptoJS.AES.encrypt(message_text, crypt_key).toString(); //DECRYPT var message_decrypt = CryptoJS.AES.decrypt(message_text, crypt_key).toString(CryptoJS.enc.Utf8);
Now it is important that for each chat that exists it should have its own randomly generated key, so that even if someone finds their own key, they can not use it to decrypt any messages they happen to receive through listening in on the MQTT topics with a wildcard. In order to stop anyone from listening in I would suggest using method 1 to stop this from happening.
To Finish off.
These Two methods both work well on their own however I would personally use methods 1 & 2 in tandem so that we can double the protection in the extremely rare case that someone learns of a clientID of another user, at least the messages will be highly encrypted.
Many thanks to @AndySc & @ralight for pointing me in the right direction for setting up a MQTT broker that is secure even over WebSockets in the browser.