Secure access to home IP cameras over the web with SSL
IP cameras are cheap these days. I have a few Foscam FI8910W cameras at home as part of my home security system. A friend recently gave me a Foscam C1 to be used as a baby monitor. I try to avoid using the manufacturer's mobile device apps for viewing the video feeds because 1) I don't want my private information (video, IP address, credentials, etc) exchanged or leaked to the manufacturer and 2) I don't want to have to use multiple apps if I buy multiple cameras from different manufacturers. I currently use tinyCam Monitor PRO on my Android device to view the video feed both on the home network and while I'm away. It works very well, is customizable, and supports many different manufacturers.
I took precautions when setting up the cameras on my home network since I know these cameras could be easily hacked with a default setup:
- Secure home network with a router running Tomato Firmware
- Use the latest firmware on the cameras
- Change the default username and password on the cameras
- Avoid using any of the manufacturer's services on the camera that makes it easy to view the video feed on the web (eg, DDNS)
- Use SSL (https) to encrypt the internet traffic/video feed
Regarding the use of SSL, newer cameras like the Foscam C1 should support it by default, so making it world-accessible is as easy as setting up a port forward on the router to the IP camera port 443 (or whatever the https port is). However, for older cameras like the Foscam FI8901W that don't support SSL, one could set up an encrypted reverse proxy using a web server like nginx. Luckily, nginx is available on my router running Tomato Firmware so I don't have to use a separate Linux server. Here's how I set this up on my router running Tomato:
- On the Administration page of the router running Tomato, enable both
http
andhttps
access to the router's administration. Check the "Save to NVRAM" box. The point of this is to create a certificate and key on the router that we could use with nginx so we don't have to generate these files elsewhere. I ssh'd into the router and found the following files:/tmp/etc/cert.pem
and/tmp/etc/key.pem
. - Go to the Web Server page of the Tomato router, and follow this guide step by step to incrementally set up a reverse proxy on nginx. Paste the final server code inside the "http" section of the web server page on Tomato (assuming we want port 1234 to be the external port for the camera, 192.168.1.100 is the camera's IP address internally, and 88 is the web port of the camera internally):
server {
listen 1234; # 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 /tmp/etc/cert.pem;
ssl_certificate_key /tmp/etc/key.pem;
# 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.1.100:88;
proxy_redirect http://192.168.1.100:88/ $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
}
}
- Every camera should have a separate server chunk like the previous.
- Set up port forwarding: external 1234 to 192.168.1.1:1234, where 192.168.1.1 is the IP address of the router.
- To make the router respond to the ports (eg, 1234) when requested from the outside world, we need to add a rule to
iptable
by pasting the following in the "Firewall" section of the Administration > Scripts page (to have it run immediately without reboot, ssh into the router and execute):
iptables -t filter -A INPUT -p tcp --dport 1234 -j ACCEPT
- Do the previous step for each camera or port. If this is not done, then the external port will not work when we access it outside the home network (the point of all this!).
- Turn on the nginx web server on the Web Server page.
- When away, go to a web browser or mobile app and point to
https://external_ip:1234
(enable SSL if using a mobile app) and the video feed should be encrypted and available.