HOWTO securely access your NVR on your Smartphone without using the hardware provider cloud (without VPN)
I see sometimes people wondering how to securely access their NVR or cameras on their smartphone (or from outside the LAN), without using the cloud servers from the hardware provider. Especially for Chinese brands that have built-in CCP backdoor...
So here's what I did and why. First, I will assume that you have some knowledge on IP network, and on how to secure the NVR and cameras on your LAN (use the firewall to block both inbound and outbound traffic on router level, segregate on a separate VLAN if needed).
What I wanted to achieve is the creation of a secure tunnel between my NVR and my smartphone, have an automatic authentication in order to make sure the smartphone is allowed (and possibly have several possible smartphone with each their own authentication), and have the tunnel working without the need to connect to my LAN (so not a VPN, just a tunnel on a dedicated port).
To achieve that I used STUNNEL
to create a double layered tunneling: one layer to create a secure TLS tunnel with a 2048 RSA key, and a second layer to have a client authentication with a 64 characters key dedicated to each smartphones.
I used my home server, but it could work on a Raspberry Pi. I also use a dedicated NVR from the same vendor as the cameras, but it could work with a VMS (and even share the same PC as the VMS). 1/ Generate certificates and keys:
You'll need to generate a certificate for the server. To do so, you can use the CLI commands:
openssl genrsa -out key.pem 2048 openssl req -new -key key.pem -out auth_cert.pem openssl x509 -req -days 3650 -in auth_cert.pem -signkey key.pem -out cert.pem
Those commands will generate a private key, then generate a certificate for signature request, and finally use that request to generate an self signed certificate for 10 years (you'll have to answer interactive questions to sign the certificate). Here the certificate is self-signed and it's enough since I check if the certificate is the correct one on the client side.
Then generate a key for each clients:
openssl rand -base64 64
And put them all in a file "psksecrets.txt" with a dedicated client name:
client_name_1:generated_key_1 client_name_2:generated_key_2 client_name_3:generated_key_3 . . . 2/ Server side:
On the server side, in the LAN, you'll need at least to install STUNNEL version 5.09 or higher.
In the "stunnel.conf" file, use a configuration like the following one that to complete the provided example:
cert = cert.pem key = key.pem [server_psk] accept = 12345 connect = 23456 ciphers = PSK PSKsecrets = psksecrets.txt [server_proxy] accept = 23456 connect = 192.168.1.123:34567 sslVersion = all ciphers = ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PS options = NO_SSLv2 options = NO_SSLv3 options = CIPHER_SERVER_PREFERENCE
In that example, 192.168.1.123:34567 is IP and port to access the NVR (for me a Xiongmai NVR). 23456 is port used to chain the two tunnels. 12345 is the entry port for the connection, it's this port that need to be forwarded to the WAN. I filtered out the weak ciphers for the first tunnel. 3/ Smartphone side:
On each smartphones, you also need to install STUNNEL version 5.09 or higher. With an Android smartphone, you can use the app called SSLSocks
, it works great.
In the client "stunnel.conf" file, use a configuration like the following one to complete the provided example:
client = yes [client_psk] accept = 23456 connect = your_domain_name:12345 PSKsecrets = psksecrets.txt [client_proxy] accept = 34567 connect = 23456 CAfile = cert.pem verifyPeer = yes
And in the client "psksecrets.txt" just copy the line for that specific client from the server file:
In that example, your_domain_name:12345 is your domain name (it also works with your public IP) and public port to access the tunnel. 23456 is port used to chain the two tunnels. 34567 on the localhost (IP 127.0.0.1) is the port and IP to use by the smartphone CCTV app you use (for instance XMEye). You authenticate using the client_name_1 key. 4/ How does it work?
The communication will work like that:
Smartphone CCTV app < [client_proxy] < [client_psk] <=WAN=> [server_psk] < [server_proxy] <=LAN=> NVR
< is traffic on localhost (internal to the device), <=LAN=> is LAN traffic, <=WAN=> is two layer tunneled WAN traffic, and  is specific STUNNEL configuration steps.
When you'll connect with the client to the first tunnel, you'll check if the server is the correct one (by checking the server certificate and comparing with a local copy of it, to avoid Man In The Middle) and establish a 2048 RSA strong TSL connection. Then the client will connect to the second tunnel using its key, and the server will allow that connection only if that same key is known in his own keys file.
That way we first make sure the server is the correct one and establish a strong connection, and after we make sure the client is allowed and establish a less secure connection on top of the first one. Keep in mind the whole second connection is done through the first one, so it's VERY secure.
The Android SSLSocks app works very well, and you can have it always ON from the startup in the background. The tunneling will establish on demand when you access the smartphone CCTV app: No need to activate/deactivate SSLSocks, it's completely transparent for the end user. And you won't be connected to your LAN like you would with a VPN.
submitted by shellbross
Certificate still valid although on revoked and on CRL
I've noticed some issue with revoking certificates on Mikrotik with external CRL.
I'm using easy-rsa on linux box (192.168.0.151
) to generate/sign/revoke certificates. some sort of small PKI
I've generated certificate, exported it as p12 and imported on mikrotik as shown below:
] /certificate> print detail
Flags: K - private-key, L - crl, C - smart-card-key, A - authority, I - issued, R - revoked, E - expired, T - trusted
0 KL T name="midgard" issuer=CN=Easy-RSA CA digest-algorithm=sha256 key-type=rsa common-name="midgard" key-size=2048 subject-alt-name=DNS:midgard
days-valid=1080 trusted=yes key-usage=digital-signature,key-encipherment,tls-server serial-number="D9D17FDF8F7EB1C67C2854EBAFAA4AC1
skid=6c3514c6f3f58370da93d8f6e4ada9853cef23f9 invalid-before=oct/30/2020 22:53:42 invalid-after=oct/15/2023 22:53:42
1 T name="CA" issuer=CN=Easy-RSA CA digest-algorithm=sha256 key-type=rsa common-name="Easy-RSA CA" key-size=2048 subject-alt-name=""
days-valid=3650 trusted=yes key-usage=key-cert-sign,crl-sign serial-number="37D39CF490CB2C4F48A98B6556B5E17907BAE12A"
skid=037b5d142c858e5ce791d2aa20530864cf9f8e76 invalid-before=oct/30/2020 22:46:09 invalid-after=oct/28/2030 22:46:09
CRL is configured as below:
Flags: E - expired, D - dynamic, I - invalid
# CERT LAST-UPDATE NUM REVOKED URL
0 D midgard oct/30/2020 23:05:39 1 http://192.168.0.151/crl.pem
as shown above, mikrotik got information from CRL that some certificate was revoked. ok, lets look on it from linux box:
index file shows cert with s/n "D9D17FDF8F7EB1C67C2854EBAFAA4AC1" is revoked:
:~/pki# cat index.txt
R 231015215342Z 201030220332Z D9D17FDF8F7EB1C67C2854EBAFAA4AC1
checking revocation list crl.pem:
:~/pki# openssl crl -in crl.pem -noout -text
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = Easy-RSA CA
Last Update: Oct 30 22:05:03 2020 GMT
Next Update: Apr 28 22:05:03 2021 GMT
X509v3 Authority Key Identifier:
Revoked Certificates: Serial Number: D9D17FDF8F7EB1C67C2854EBAFAA4AC1 Revocation Date: Oct 30 22:03:32 2020 GMT
Signature Algorithm: sha256WithRSAEncryption
Any idea why from Mikrotik end, certificate is visible as valid ?
EDIT: RoS version: 6.47.7
submitted by babujnik