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!)

Just so you know, this isn’t a post about how to make an MQTT chat with javascript, this is more how to make it secure and safe.

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.

Be aware of wildcards with MQTT topics. Because we are using web sockets with javascript all and any credentials to connect to the broker will be visible, essentially anyone can now connect to your MQTT broker, even if you have credentials set. (this is the main issue with MQTT over web sockets that I know of.) So now all someone has to do is connect and subscribe to # and suddenly they are receiving all the messages all the users are sending to each other.

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

Now this is a very useful method to use when it comes to sending any messages however due to the nature of how MQTT brokers work with wildcards, I would suggest using it in tandem with method 1. At least for using mqtt on a browser with javascript and web sockets as all connection strings are publicly visible.

This is a relatively simple security method, for any messages being sent through MQTT we encrypt it before sending and decrypt it once received

First we need to include this javascript library, this is a crypto-js library which specifically includes the AES encryption method.

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>

Once we have this available in javascript we can freely encrypt & decrypt messages coming and going through MQTT using the following functions.

//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.

Leave a Reply

avatar
  Subscribe  
Notify of