MTLS on Nginx that works with client side Android Apps?

Is there a way to pull off MTLS/Two-Way SSL/Client Certificates that work on unrooted v10+ Android Clients on the cheap?

I have a couple of personal api end points that I want to be publicly accessible for just me and a few family members but filter all other traffic out like bad bots, exploit scanners or any nosey clients on the same gateway. I have been using IP filtering which works for the bots but still exposes to any device on the whitelisted ip.

Currently I reverse proxy the end points through subdomains on Nginx then filter access with DDNS IP whitelist and 444 the rest. Another option available for restricting access with Nginx is through Client Certificates/MTLS. This seemed like a perfect fit, I can get Nginx to request a client certificate as optional, and 444 all traffic except matching mapped ssl_client_fingerprint’s. This would be a tighter setup than just IP.

I went though and created my own Private EC Root CA’s, Intermediary Server CA’s and client certificates all signed and and chained together and packaged in a PFX with OpenSSL. On MacOS and Windows, everything works great and as expected in browsers and through Apps that access the API’s. Nginx gets fed the proper certificate back from clients and allows matching fingerprint hashes in or else drops the connection.

On Android 10+, everything works the same when accessed through a browser, perfect. Trouble comes when I try to access the API’s though Android Apps, Nginx gets no client certificate response.

From what I have gathered, this kind of setup used to work, maybe Android <=7 was where things changed. My understanding is that from 8+, Android Apps no longer trust User Trust Stores/Private CA Client chains at all by default, only Public System Stores unless they explicitly allowed to do so in the apps manafest/network security settings before compiling the APK? I’m assuming there is a valid and necessary security reasons for the changes.

Is there still a way to make this work on the cheap? This is what I think my options are:

  1. Buy a Public Well-Known CA that I can sign client certificates with? Not sure if I can get away with a cheap DV or if it has to be something much more complicated and expensive?

  2. Setup OpenVPN service on the server and tunnels for just the apps that need access. Seems overkill compared to client certificate. I’m using a small VPS, less overhead is the better option for me.

  3. Hand roll open source APKs of said Android Apps to allow User Trust Stores. Seems like a pain in the …

  4. Root all devices to force cert auth. Not an option for me for all the needed devices.

  5. Stick with IP whitelists. Not perfect but it does work at keeping the bad scanners out.

Does anyone have any alternative recommendations I may not know about, suggestions or corrections to what I am trying to do above?

Cheers

Answer

I ended up using Wireguard and so far it seems to be light on resources.

I filtered the Wireguard port with the DDNS whitelist since I already had it in place then I changed Nginx to allow peers from the VPN or else they must have a valid Client Cert that has it’s hash mapped or else they 444. Then Android apps can use the VPN tunnel for specific apps that need them and then all others can use the normal setup with certificates.

Attribution
Source : Link , Question Author : Ampersand , Answer Author : Ampersand

Leave a Comment