|
"It is quiet here and restful, and the air is delicious. There are gardens everywhere and police spies lie in the bushes ... " - Maxim Gorky |
It is very tempting to use the ubiquitous HTTP web protocol for IoT. It is easy to test, and lets you operate your IoT from smartphones, tablets, desktops and even a computer program. Such a setup is called RESTful. It simply means your IoT device speaks the language of the web browser and web server.
So we rush ahead with our RESTful API, and the IoT device is soon working and indispensable. Pretty soon we realize we need security and privacy: it won't do to have a hacker open the voice-controlled garage door ...
Our first line of defense is our WiFi password. It is reasonable to assume those living in the house should have access to WiFi and IoT. But what if we had guests or lodgers? Changing WiFi passwords can be a real bear, especially if you have 20-odd IoT devices. In fact it makes sense to localize the changes to a dedicated IoT server. RESTful, naturally.
We will be needing some form of authentication: account names and passwords should do for now. Next we will need a reasonable amount of privacy, i.e., encryption so that someone else should not be able to lift the IoT password off the WiFi. That means HTTPS, or HTTP with SSL.
We start by implementing HTTPS server on a Linux system. The ESP8266 is known to be a little wobbly running HTTPS. ESP32 is better, but we can do without the complication for now. The traditional way is to use Apache. There are other, easier ways (like nginx, nodejs and even python) but Apache lets you run multiple servers right off the bat. This means you can keep your bad old HTTP server, add another HTTPS server on top of that and lets you support both your HTTP and HTTPS IoT devices.
From a bog-standard Debian (mine is a Beaglebone on eMMC), do the usual:
# apt-get update
# apt-get upgrade
# apt install apache2
Apache should come up complete with the stock webpage at http://localhost. Put your webserver files at /var/www/html/
To access the webserver from outside your WiFi access point, you will need a DNS server, but once you get it organized, a bog standard browser will display a warning before it will display your home page:
That means you need SSL, which usually costs money. You can opt for a self-signed certificate but this will produce a warning with most browsers. You then elect to disregard the warning and proceed, but this is a real problem if you are trying to sell the IoT device.
One way out is to get a 90-day certificate free from
sslforfree. You just have to register, input your domain name and prove that you have access to the webserver, usually by uploading an sslforfree file to it. After it checks out the certificates can be downloaded.
sslforfree links to a youtube video describing the process.
Do check out the video. I will simply list the differences relevant to a Debian installation. In Debian it is a simple:
# a2enmod ssl
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create s
elf-signed certificates.
To activate the new configuration, you need to run:
systemctl restart apache2
I now need a configuration file for my HTTPS (or SSL) webserver. There is a template in Debian:
# cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/secure.cmheong.duckdns.org.conf
secure.cmheong.duckdns.org being the domain name of my new HTTPS server. The parameters for the new server are put in:
# cat /etc/apache2/sites-available/secure.cmheong.duckdns.org.conf | head -n 16
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName secure.cmheong.duckdns.org
ServerAlias www.secure.cmheong.duckdns.org
ServerAdmin webmaster@secure.cmheong.duckdns.org
DocumentRoot /var/www/html
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/secure.cmheong.error.log
CustomLog ${APACHE_LOG_DIR}/secure.cmheong.access.log combined
You then check your configuration and do not proceed further until this passes:
# apachectl configtest
Syntax OK
Make sure your webserver is now accessible from the Internet. Usually this means setting up Port Forwarding in your gateway to forward all port 443 traffic to your server IP address.
# systemctl restart apache2
You will then need to prepare for the sslforfree test of webserver and domain name ownership:
# mkdir /var/www/html/.well-known
# mkdir /var/www/html/.well-known/pki-validation
Register with sslforfree, download the challenge file they provided and put it in the new directory. This is where the Debian ssh installation comes in handy.
If the sslforfree challenge succeeds, then the certificates and private key will be generated as a zip file.
# unzip secure.cmheong.duckdns.org.zip
Archive: secure.cmheong.duckdns.org.zip
extracting: certificate.crt
extracting: ca_bundle.crt
extracting: private.key
You then move them to their final secure directories:
# cp -v ./sslforfree/*.crt /etc/ssl/certs
'./sslforfree/ca_bundle.crt' -> 'certs/ca_bundle.crt'
'./sslforfree/certificate.crt' -> 'certs/certificate.crt'
# cp ./sslforfree/private.key /etc/ssl/private/private.key
Remember to delete the ./sslforfree directory. If you want to put the certificates in a different place you will need to update the site config file accordingly:
# cat /etc/apache2/sites-available/secure.cmheong.duckdns.org.conf | grep -i SSLCerti
# SSLCertificateFile directive is needed.
#SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
#SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
SSLCertificateFile /etc/ssl/certs/certificate.crt
SSLCertificateKeyFile /etc/ssl/private/private.key
SSLCertificateChainFile /etc/ssl/certs/ca_bundle.crt
As usual test the Apache configuration:
# apachectl configtest
And then restart Apache:
# systemctl restart apache2
The just aim your Chrome browser at https://www.yoursecureserver.com. If it worked you get something like this:
Now the traffic to and from the IoT RESTful server is encrypted. Note the sslforfree certificates expire in 90 days, but you are free to generate a new set. They will even email you a reminder.
There you have it: a secure Internet-facing RESTful IoT server.
Happy Trails.