And if you desire is for a comprehensive, robust server, your IT infrastructure has to include all of these systems.
Monitis has put together a checklist of 101 actions you can take to maximize security around LAMP. Hopefully we’re shedding a little light around this issue for you to give you some new ideas on how to make administering your system easier — so that, in turn, you can focus on more strategic tasks. You can find previous posts about increasing security around Linux and Apache, but, in today’s post, we’ll offer tips on LAMP security around MySQL — a powerful open-source database.
If a database user needs “read” access to two tables, you should not be giving that user full access to the entire database server. The problem is that novice database administrators will often grant full access to new MySQL users, either on a whole database or on the whole database server. Don’t make that mistake, read up on MySQL’s GRANT statements and how to use them.
Many web applications have distinct areas, some of which need only “read” access, while other areas might require “write” access to one or two tables, and yet other areas require write access to most of the database. Consider creating separate accounts for each area and walling the areas off. Also, double-check whether the payment processing code really needs full access, or whether INSERT access is sufficient. Use fine-grained security controls and keep up-to-date, relevant, documentation.
As with Apache, you should use SSL/TLS with MySQL as well. This may not be relevant if your database server is on the same host as your web server, but often enough it isn’t. Use “stunnel” to establish a secure connection between Apache and MySQL to prevent attackers from sniffing out your precious passwords.
Just like Apache, you should configure your MySQL server to send its logs to the syslog server. If you use a remote syslog daemon, check your setup: Make sure that the correct error levels are being logged, and that the log messages actually arrive on the other end. (See our blog
Apache and MySQL Logging with Syslog-ng)
The “user” table in MySQL is a rather precious table that only administrators should have access to. Disable access to the user table for all users except root — and any other administrative accounts. This applies to read and to write access, though, of course, you should be especially watchful with regards to write access.
As dumb as this sounds, the default MySQL installation often does not set a password for the “root” user. You wouldn’t leave your system root password empty, so you shouldn’t leave your MySQL root password empty either. This is a good chance to check that all the other accounts have passwords set as well.
Don’t store plain-text passwords in your database, ever! The rule is as simple as that. In fact, don’t store plain-text passwords anywhere.
Hopefully at this point you’ve already configured iptables to disallow external access to your MySQL server. Just in case, you should tell MySQL not to accept connections from any hosts other than localhost. You might ask yourself what you should do if you need to connect externally? Remember, external connections should go through stunnel! To MySQL, it will look as if the connection is coming from localhost.
You should already be running Apache in a dedicated user account. Do the same with your MySQL server. Make up your own name and remember that non-default names are often good for security. You probably know this, but just in case: Don’t run your MySQL server as root, and don’t run it as “nobody”.
MySQL, as any other program, needs to store its data somewhere. Configuration is stored in /etc, of course, but where does the actual data go? This is installation-specific. The default location is /usr/local/mysql/data. Please make sure that this directory has very restrictive permissions, as it will include the “user” table. It will obviously also include your application data, which may or may not be sensitive.
Allowing an attacker to modify your MySQL configuration is a big security issue. They could simply reset your MySQL root password and they’d get away with it. Make sure my.cnf is only root-writable, and enforce this with a tripwire program.
Like using a non-default SSH port, using non-default user names is only going to help your system’s security. As a minimal security measure, rename your MySQL root user to something other than “root”. For added security, consider naming your web application user something other than “www”, “php”, “web”, or “app”.
“test” user. Default user accounts are a real chore to remove, though if you remove the default “test” user account, you also get a lot of security in return. This “test” user is usually not protected with a password and can be a first entry point for an attacker. You can protect yourself from being low-hanging fruit.
There are four “special” permissions that you have to watch out for: PROCESS, SUPER, SHUTDOWN, and FILE. The short version: Only “root” should have these permissions. The longer version is that they allow the calling user to shutdown your database server and change server variables, among other nasty stuff.
For speedy data loading, “LOAD DATA LOCAL INFILE” can be a real charm. You may want to enable it when you first deploy your database server. After that, you should disable this command, as it allows an attacker to read all local files that your MySQL server has access to.
History files like “.mysql_history” often contain passwords from previous sessions. The same goes for your “.bash_history” if you’ve entered a MySQL account password on the command-line in the past. Check your history files and remove any passwords that you find and that shouldn’t be in there.
Yes, disaster recovery falls in the “information security” category. Backup your databases and automate the process. The backups are obvious, but how about the automation? You’ll find that you won’t be as inclined to forget to run an automated process, because it runs itself. This only goes so far, as you can’t fully automate exchanging tapes, but the further you automate the process, the more reliable it becomes. Oh, and don’t forget to test those backups!
Enable logging for all connections and queries where you can. Logging all queries can be a real performance killer, so you have to make a trade-off. Yet, isn’t security always a matter of trade-offs. Log as much as you reasonably can and you’ll be thankful when someone does break in.
Consider installing a database firewall to protect against SQL injection, but also against exploits against the database. Database firewall solutions are hard to find and often quite expensive, so you have to consider if this is worth it. You should definitely take a look.
Of course, another great way to boost security of your MySQL database is to employ a 24/7 monitoring service like Monitis. We operate whether your firewall is up or down, so there’s never any need to worry about downtime — at least on our part!