littlebizzy / slickstack

Lightning-fast WordPress on Nginx
https://slickstack.io
GNU General Public License v3.0
629 stars 112 forks source link

Adminer is public-facing by default and should be more secure #73

Closed blakepb closed 7 months ago

blakepb commented 3 years ago

Adminer is public-facing by default. SQL tools like Adminer and phpMyAdmin, while convenient for quick administration tasks, greatly increase the attack surface of a site when they are public-facing. I think requiring manual "installation" of Adminer would be a better practice. Having Adminer along with any future backend tools run on an alternative port (which users are encouraged to lockdown by firewall) would probably be best practice.

Edit: Looks like Adminer required manual "installation" via ss-install-adminer in the past. I guess I would urge a return to that?

LCBO commented 3 years ago

This is a security flow detected by Detectify services as well. There are not important flows but this.

jessuppi commented 2 years ago

Thanks for your feedback on this @blakepb

The reason why we install Adminer by default is because we aim to make SlickStack as easy to use as possible for newbies who don't have much DevOps experience (and more importantly, potential freelancers).

That said, although our security overall has been very strong I think, Adminer has been ignored for too long. The challenge with securing Adminer is how to make it easy to use for newbies, but still making it as secure as possible...

Here's some of the ideas that I have seen around the web:

It's important to note that SlickStack does already have SSL/HTTPS for Adminer, and this is because it loads via PHP-FPM in the Nginx server block on port 443 already. If we changed the port number, we'd have to customize SSL configuration which seems a bit janky, and requires more "moving parts"... I'm not against "security by obscurity" per se, and previously SlickStack did use port 6969 by default for SSH (for example), but some of that is kinda gimmicky and unserious IMO.

We also already rate-limit the Adminer URLs using Nginx zone settings -- that could possibly be better optimized, but it's definitely active and working already, at least.

As a fairly technical person myself, who uses a variety of devices and travels sometimes, I can't imagine requiring SSH keys and/or port forwarding to a local computer, etc, just to access Adminer, and I know the majority of clients I work with and their freelancers wouldn't be able to figure that out either, so that's a no-go I think.

We recently added the ability in SlickStack to restrict sudo SSH sessions to a specific IP address, since SlickStack defaults to discouraging SSH key usage, this was a requested alternative that seemed to make sense. However, restricting Adminer to certain IP addresses would probably confuse and frustrate most typical WordPress users... unlike SSH, which is certainly a more technical thing to begin with, Adminer is something that your average web designer might require.

And since SlickStack supports only a single site per server, the non-root database user already has access to production, staging, and dev databases, just like the admin@127.0.0.1 user, so disabling access for the "root" user wouldn't really add any more security on its own for our purposes...

Ref: https://serverfault.com/questions/445294/securing-phpmyadmin-non-standard-port-https Ref: https://www.tecmint.com/secure-phpmyadmin-centos-ubuntu/ Ref: https://gripfastistech.com/index.php/blog/54-how-to-protect-adminer-by-ip-address-on-nginx.html Ref: https://stackoverflow.com/questions/3687940/how-to-restrict-access-to-phpmyadmin Ref: https://stackoverflow.com/questions/2631269/how-to-secure-phpmyadmin

jessuppi commented 2 years ago

In summary:

We use SSL, rate-limiting (anti-brute force), and single site per server already (isolation), and the default passwords that SlickStack generates for database users are pretty strong.

Right now I think the only practical and user-friendly additions we might consider would be changing the Adminer URL to make it less guessable for bots, and/or consider enabling password protection via Nginx.

We also have a new option in ss-config for disabling Adminer, although it's not actually functional yet.

jessuppi commented 1 year ago

Another potential approach here might be requiring user authentication via /wp-admin/ before access to adminer.php is allowed, but I'm not sure if that would introduce as many drawbacks as benefits, e.g.:

https://wordpress.org/plugins/db-access-adminer/

There's been several such WP plugins over the years, although I recall some security concerns in the past.

Honestly this could be the best approach, as then security concerns would come mostly down to file permissions, and then whatever existing security exists for /wp-admin/ and wp-login.php etc.

I would have to consult with some WordPress devs to try this probably, or get some help.

jessuppi commented 7 months ago

For now, I'm going to proceed with generating random strings for the Adminer frontend URL, that seems to be the easiest improvement here, and also no risk of complicating things (e.g. using Nginx/WP authentication).

jessuppi commented 7 months ago

Okay, well there are too many commits to reference here. But see:

https://github.com/littlebizzy/slickstack/blob/master/modules/nginx/sites/production.txt

And:

https://github.com/littlebizzy/slickstack/blob/master/modules/wordpress/mu-plugins/xxx-common.txt

These now have a placeholder @ADMINER_RANDOM_URL which is replaced with the value of ADMINER_URL during the initial ss-install process, unless a value exists already for that variable in ss-config. So maybe this is good for some users who want to keep an easy-to-remember URL like /adminer/ or whatever, but that now requires opt-in and by default the Adminer frontend access URL will be a difficult to guess string generated by OpenSSL.