Securing MQTT communication between Ardruino and Mosquitto
2016-07-01 11:55
344 查看
I tried a lot of solutions, experimented heavily, but this was the most consistent way for my monitoring and remote command design. Your mileage may vary (greatly) based on your use case.
As I posted late in the summer, connecting and interacting with an Arduino remotely with MQTT and web sockets is fairly straight forward. Dealing with the security however is not so trivial.
While we can make the ATmega328 do many things, doing secure socket layer (SSL) isn’t an option. Which leaves us with a bit of a dilemma before we even get started: how do we secure communications? If we just use the username and password authentication available
within both the MQTT libs for Arduino and Mosquitto, we’re passing them in the wide open. Anyone with Wireshark and a couple minutes will start opening your garage door.
In a perfect world, Arduino does SSL (or maybe we’re using Rasberry Pi’s or Netdruino’s) and we don’t have any need for a middle man. However, it’s not a perfect world, and we have lots of Arduino’s we want to securely control from the outside world. We need
a middle man.
In our case, our middle man is a local instance of Mosquitto that we’ll run bridged to our outside instance. We’re making a few presumptions (in particular that your home network isn’t wide open and is secured), but let’s for a second pretend you have some
device that’s always running. In my case, that happens to be a netbook that has been re-purposed as a print server, so it’s not seeing constant action.
Okay, so now our Audrinos are talking and listening the the local instance of Mosquitto. The local network is locked down, so we’re not worried about line snooping. Let’s start simple, and bridge our local Mosquitto instance with our remote Mosquitto instance.
Bridging Mosquitto instances is fairly well documented (see mosquitto.conf documentation). Sticking with the
sane defaults, creating the bridge is like so:
Breaking down the config, we’re securing the bridge connection for using SSL (to see how to generate the certs and keys, have a look at the mosquitto-tlsdocumentation),
we’re using a username/password, and we’re defining which topics we’re sending out and listening for.
Topic mapping is important, but slightly out of the scope of the security conversation…but I’m going to talk about it anyway. Topic mapping defines which messages will flow across the bridge. It can be very easy to create a loop, where both brokers continuously
send the same message back and forth. This is beyond problematic; you will anger the CPU gods and make your broker machines unhappy.
What to do? It really depends on how your overall information design. For me, I remap from the local devices tree into the remote home/devices/+ and to be super paranoid, I add an access control list rule that only allows the bridge user to write to that tree.
So you’ve created this bridge, but your remote server needs some options set as well in it’s own config to make all this work. For the sake of not being open at all on the remote end, let’s not allow anonymous access, require password, and set the defaults
to use SSL.
To create the password file, you can use mosquitto_passwd. The access control file will differ based on your
information design, but I basically set up some limits on the users that I’ve defined for my over all system. You could very well not use acl’s and the SSL and password file will suffice.
I’m not going to go indepth on pre-shared keys, but if you’re interested in knowing, you could very well use PSK and not use the password_file at all.
In the end we end up with two Mosquitto brokers; one in the outside world that only speaks to the web socket server, and one on our inside private network, which only talks to the Arduinos. Together, the two brokers talk over SSL through the bridge.
Since the python Mosquitto library has SSL support, it talks to the outside instance securely. We then run our dashboard and interface panel over HTTPS, which further secures information exchange. And because we’re running HTTPS, the web socket service will
use WSS (WS over TLS), also secure.
It’s a rather long path to secure everything, but in the end, as long as we make sure we don’t have any gaps in our local network, we can still talk securely and control those Arduinos remotely.
As I posted late in the summer, connecting and interacting with an Arduino remotely with MQTT and web sockets is fairly straight forward. Dealing with the security however is not so trivial.
Captain, we need more power (for the SSL)
While we can make the ATmega328 do many things, doing secure socket layer (SSL) isn’t an option. Which leaves us with a bit of a dilemma before we even get started: how do we secure communications? If we just use the username and password authentication availablewithin both the MQTT libs for Arduino and Mosquitto, we’re passing them in the wide open. Anyone with Wireshark and a couple minutes will start opening your garage door.
Sometimes you need a middle man
In a perfect world, Arduino does SSL (or maybe we’re using Rasberry Pi’s or Netdruino’s) and we don’t have any need for a middle man. However, it’s not a perfect world, and we have lots of Arduino’s we want to securely control from the outside world. We needa middle man.
In our case, our middle man is a local instance of Mosquitto that we’ll run bridged to our outside instance. We’re making a few presumptions (in particular that your home network isn’t wide open and is secured), but let’s for a second pretend you have some
device that’s always running. In my case, that happens to be a netbook that has been re-purposed as a print server, so it’s not seeing constant action.
Building bridges
Okay, so now our Audrinos are talking and listening the the local instance of Mosquitto. The local network is locked down, so we’re not worried about line snooping. Let’s start simple, and bridge our local Mosquitto instance with our remote Mosquitto instance.Bridging Mosquitto instances is fairly well documented (see mosquitto.conf documentation). Sticking with the
sane defaults, creating the bridge is like so:
#... previous things address ec2-somethingsomething.us-west-1.compute.amazonaws.com:8883 connection BridgeIt topic devices/# out "" home topic cmds/# in remote "" username SomeUser password SomePassword bridge_cafile /etc/keys/myCA.crt bridge_certfile /etc/keys/myServer.crt bridge_keyfile /etc/keys/myServer.key #... other things
Breaking down the config, we’re securing the bridge connection for using SSL (to see how to generate the certs and keys, have a look at the mosquitto-tlsdocumentation),
we’re using a username/password, and we’re defining which topics we’re sending out and listening for.
A note on topic mapping: don't loop me
Topic mapping is important, but slightly out of the scope of the security conversation…but I’m going to talk about it anyway. Topic mapping defines which messages will flow across the bridge. It can be very easy to create a loop, where both brokers continuouslysend the same message back and forth. This is beyond problematic; you will anger the CPU gods and make your broker machines unhappy.
What to do? It really depends on how your overall information design. For me, I remap from the local devices tree into the remote home/devices/+ and to be super paranoid, I add an access control list rule that only allows the bridge user to write to that tree.
Locking up the remote side
So you’ve created this bridge, but your remote server needs some options set as well in it’s own config to make all this work. For the sake of not being open at all on the remote end, let’s not allow anonymous access, require password, and set the defaultsto use SSL.
#... previous things acl_file /etc/mosquitto/accesscontrols allow_anonymous false password_file /etc/mosquitto/users bind_address 127.0.0.1 port 8883 cafile /etc/keys/ca.crt certfile /etc/keys/server.crt keyfile /etc/keys/server.key #... other things
To create the password file, you can use mosquitto_passwd. The access control file will differ based on your
information design, but I basically set up some limits on the users that I’ve defined for my over all system. You could very well not use acl’s and the SSL and password file will suffice.
I’m not going to go indepth on pre-shared keys, but if you’re interested in knowing, you could very well use PSK and not use the password_file at all.
So where does this leave us?
In the end we end up with two Mosquitto brokers; one in the outside world that only speaks to the web socket server, and one on our inside private network, which only talks to the Arduinos. Together, the two brokers talk over SSL through the bridge.Since the python Mosquitto library has SSL support, it talks to the outside instance securely. We then run our dashboard and interface panel over HTTPS, which further secures information exchange. And because we’re running HTTPS, the web socket service will
use WSS (WS over TLS), also secure.
It’s a rather long path to secure everything, but in the end, as long as we make sure we don’t have any gaps in our local network, we can still talk securely and control those Arduinos remotely.
相关文章推荐
- IOS UITableView代码添加数据源和指定委托
- UIScrollViewDelegate详解
- intellij idea自动生成serialVersionUID
- hive & hue 中文乱码的问题
- JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue
- TIPTOP GP5.1 实现链接网页方法 ui.Interface.frontCall
- 谷歌原生自动化框架UiAutomator1.0
- iOS VoiceOver Programming Guide
- JavaGUI版本销售管理系统
- HDU——1242Rescue(BFS+优先队列求点图最短路)
- UIBezierPath精讲
- 自定义View重绘使requestLayout, invalidate和postInvalidate的异同
- UGUI Text组件实际文本宽高的获取
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
- tableView设置UITableViewStyleGrouped顶部有空余高度
- Starting MySQL...The server quit without updating PID file
- UIToolBar barItem的位置
- 启动安卓模拟器报错 emulator: ERROR: x86_64 emulation currently requires hardware acceleration! CPU acceleration status:HAXM must be updated(version 1.1.1<6.0.1) 解决办法
- 在iOS8中使用UIAlertController
- Android Studio 运行时出现 finished with non-zero exit value 2 错误分析