Securing remotely accessible IP cameras that do not support HTTPS
I'm going to assume your router isn't smart enough to set up an encrypted reverse proxy by itself.
Conventions Used Below
- Home IP Address: 1.2.3.4 ( google search my ip to find yours )
- WebCam IP Address / Port:
192.168.0.123
on port 456. - Linux/Unix Computer Running Reverse Proxy:
192.168.0.101
Initial Checks
On local network can you see webcam at http://192.168.0.123:456
? Great. Can you not connect to webcam from the outside world (that is http://1.2.3.4:456
is firewalled off)? Great. If not reconfigure your webcam and port forwarding/firewall rules on your router.
Next, install a webserver on a computer on your local network that is on whenever you want to connect to your webcam. I'm going to assume linux/unix and give instructions for nginx.
As a initial test, set up a reverse proxy with no encryption. Install the latest version of nginx, edit the configuration file (/etc/nginx/conf.d/default.conf
) and add lines similar to:
server {
listen 8080;
location / {
proxy_pass http://192.168.0.123:456;
} # replace with your webcam's local IP address and port.
}
Now restart nginx (sudo /etc/init.d/nginx restart
) and try connecting to the proxy (http://192.168.0.101:8080
) and it should work just like if you went to http://192.168.0.123:456
. If you have trouble, check everything again or consult the nginx documentation.
Getting A TLS/SSL Certificate
Now you need to add a SSL certificate and the associated private key. You can generate one signed by a certificate authority (e.g., from startssl.com for free) or generate one yourself that is self-signed (and will not be initially trusted by web browsers). Setting up a CA-signed certificate will be more complicated for a home network where you'll have to get a domain name (that you can prove to the CA you own), set up dynamic DNS to that domain name, etc. (If you are trying to get started with Dynamic DNS - https://freedns.afraid.org/ is a great place to start).
To generate a self-signed certificate, first use openssl to create a private key (in this case a 4096-bit RSA private key):
# openssl genrsa -out private.key 4096
If you are curious you can view the contents with openssl rsa -in private.key -text -noout
. Next you need to generate a certificate based on that private key, which can be done with:
# openssl req -new -x509 -key private.key -out yourcert.crt -days 3650
The 3650 says it will expire in 3650 days (~10 years). Openssl will prompt you for more details, feel free to leave them blank or put any information in there. (You can view the content of your certificate with openssl x509 -in yourcert.crt -text -noout
).
Now put your private key and certificate somewhere safe (e.g., in /etc/ssl/private/private.key
and /etc/ssl/certs/yourcert.crt
), restrict their permissions (make sure owned by root and no one else has read/write permissions).
Turn on SSL in Reverse Proxy
Then edit your nginx server configuration file to enable SSL as follows:
server {
listen 443; # doesn't have to be port 443 - could be any port (say 8080) if you
# connect via https://192.168.0.101:8080 . But on port 443
# you can just use https://192.168.0.101
ssl on;
ssl_certificate /etc/ssl/certs/yourcert.crt;
ssl_certificate_key /etc/ssl/private/private.key;
# certificate and private key where you just placed them
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
# reasonable SSL configuration, disable some known weak ciphers.
location / {
proxy_pass http://192.168.0.123:456;
proxy_redirect http://192.168.0.123:456/ $scheme://$host:$server_port/;
# If your webcam (or other proxied application) ever gives URLs in the HTTP headers
# (e.g., in a 302 or 304 HTTP redirect),
# the proxy_redirect line changes the URL in the HTTP header field
# from http://192.168.0.123:456/some/path to https://192.168.0.1:8080/some/path
}
}
Restart nginx, and now you should be able to connect to your webcam on your local network at https://192.168.0.101
(you'll get warnings about certificate being untrusted as it is a self-signed certificate).
Setup port forwarding in your router
The final step is to configure your router to do port forwarding. That is when you connect to https://1.2.3.4
(port 443) from the outside world, set it up to port-forward to 192.168.0.101
(port 443). Possibly set up dynamic DNS so if your home IP address changes it still points to the right place. Some ISPs do block port 80 and 443, so you may have to change it to some other port.
Be careful about how you connect. I've noticed many IP camera programs do not check certificates for trust (as they are often self-signed), so an attacker could possibly do a MitM attack by inserting a different self-signed certificate. It's best if you add your self-signed certificate to be trusted on your own browsers and reject it if it changes.
Your router merely forwards packets, whichever protocol is behind it dictates the security. You can indeed, as you mentioned, would be a reverse proxy that listens on a HTTPS connection, and forwards everything to an HTTP connection. This can be done easily using Apache's mod_proxy.
Alternatively, it may look a bit like overkill, but a good way would be to set up a VPN you can connect to. This can be done easily (and free) with OpenVPN. You'd securely terminate a tunnel on your local network, and then you can access all internal resources. This may give you more flexibility in the future; you can access your entire network.
Either way, eavesdroppers won't see anything, since you're tunneled in an encrypted, authenticated connection.