Securing a LAMP server (Part 2)

lamp imageThe first part of this series on securing a LAMP server setup focused on hardening Apache (the popular web server) this article will focus on securing both MySQL and PHP. This is a fairly straight forward process and should be done by every web server administrator, regardless of software and technologies used.

The topics discussed in these articles are just best practices and recommendations, and are by no means a definitive list, you should always go out and research finding more ways to secure your server, possibly better ways. Some requirements may not be exact or match what your server configurations are or what your users need, as such rather than just blindly copying what is here, try to understand what is going on and configure it to reflect your own servers setup.

As a side note, this will not completely eliminate all potential threats, it should however mitigate some attacks, and make others more difficult, some attacks such as DDoS are near impossible to defend against (depending on the scale of the attack) but some of the techniques described should lower the impact these have.

MySQL security

Disable remote access – Firstly you should locate where your mySQL config file is, it’s generally either /etc/my.cnf or /etc/mysql/my.cnf to force MySQL to only listen on localhost you should add the following to that file:


Disable LOCAL INFILE – This disables unauthorized reading of local files from MySQL, again add to my.cnf:


Change root username and password – Since “Root” is the default administrator username it is also what attackers are most often after access to, to make this task harder you should change the username and the password (preferably with a long alphanumeric password) To do this in the MySQL console type:

mysql> RENAME USER root TO new_user;
mysql> SET PASSWORD FOR 'new_user'@'%hostname' = PASSWORD('newpass');

Remove the “test” database– By default this is created as a test space and can be accessed by the anonymous user, this is often used as an attack launchpad and can be disabled by:

mysql> drop database test;

Remove obsolete accounts– To check if there are any users with blank passwords (as comes with default) use the following:

mysql> select * from mysql.user where user="";

If there are any lines echoed back you can remove them with:

mysql> DROP USER "";

Lower system privileges– You should make sure the file directory where the database is stored is owned by the users “mysql” and “root”, the group “mysql” should have access and no others, you can check with:

ls -l /var/lib/mysql

The binaries should only be accessed by the specific users “mysql” and “root” these are generally stored in /usr/bin you can check these with:

ls -l /usr/bin/my*

Lower database privileges– This requires being vigilant and knowing what permissions each user should have. Be careful with the SUPER privilege as it allows users to manipulate server configurations. you can see a list of users with the SQL command:

mysql> select * from users;

and view each users permissions with:

mysql> show grants for ‘username’@’localhost’;

You should however disable the SHOW DATABASES privilege which is used for information gathering, to do this add the following in the [mysqld] section of the my.cnf file:


Enable Logging– Again this should be added to the [mysqld] section of you my.cnf file:

log =/var/log/mylogfile

There is sensitive information stored in the log files generated by MySQL so it is recommended that you verify that only “root” and “mysql” have access to those files

Run in a Chroot environment – much like apache it is highly recommended that you run MySQL in a jail, and doing so is much easier, firstly create the directory /chroot/mysqlthen in the [client] section of my.cnf add:

socket = /chroot/mysql/tmp/mysql.sock

Remove history– MySQL history includes lots of sensitive information, every command previously executed being one of them (remember the password changes) and this is all stored in plaintext, you should make it a habit to periodically delete this with the command:

cat /dev/null > ~/.mysql_history

Require secure passwords– back to my.cnf you want to add under the [client] section:


This will prevent connections to the database using old passwords (pre-4.1)

Encrypt client-server transmissions– To check to see if you have SSL installed run the following in the MySQL console:

mysql> show variables like "%ssl%";

If it returns “DISABLED” it means it’s available, otherwise it would say “NO”.
Step 1 of 3 is to generate ssl keys, you can do that by running:

sudo su -
cd /etc/mysql
openssl genrsa -out ca-key.pem 2048;
openssl req -new -x509 -nodes -days 1000 -key ca-key.pem -out ca-cert.pem;
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout server-key.pem -out server-req.pem;
openssl x509 -req -in server-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem;
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout client-key.pem -out client-req.pem;
openssl x509 -req -in client-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem;

Once that has completed it’s just a case of adding those into the my.cnf file:



Finally you can restart the MySQL service:

sudo service mysql restart

If you want to force the use of SSL you have to change it on a per-user basis by adding “REQUIRE SSL” to their permissions

PHP security

There isn’t really much you can do to protect PHP other than adhering to programing best practices. Since this is an article for server administrators and not developers I won’t get into them. However there are a few things you can add to the local php.ini file, usually found at /etc/php.ini or /usr/bin/php/php.ini this however is completely dependant on your server and how it has been installed. Hopefully you have found it, now you can open it with any text editor and here are some variables you might be interested in adding:

; php.ini
session.use_only_cookies = 1   ; Sessions IDs only as cookies
allow_url_fopen = Off          ; Disable URLs for file handling functions
register_globals = Off         ; Disable global variables as input

open_basedir = /var/www/htdocs/files   ; Restrict file handling functions to a subdirectory

safe_mode = Off                          ; Disable this, the next is often more practical
safe_mode_gid = On                       ; Enable safe mode with group check
safe_mode_exec_dir = /var/www/binaries   ; Restrict execution functions to this directory
safe_mode_allowed_env_vars = PHP_        ; Restrict access to environment variables

disable_functions = show_source, system, shell_exec, exec, passthru, phpinfo, popen, proc_open, proc_nice

max_execution_time = 30    ; Max script execution time
max_input_time = 60        ; Max time spent parsing inputs
memory_limit = 16M         ; Max memory size used by one script
upload_max_filesize = 2M   ; Max upload file size
post_max_size = 8M         ; Max post size

display_errors = Off      ; Do not show errors on screen
error_reporting = E_ALL   ; What errors should be reported
log_errors = On           ; Log errors to log file
expose_php = Off          ; Hide presence of PHP

Suhosin – This is a part of the “hardened PHP project” it’s a protection system for PHP to protect against a whole load of flaws and vulnerabilities. Their website explains a lot better and gives detailed instructions on how to implement this.

Conclusion – Well I hope you have learnt something from these two articles and hopefully implemented some of the ideas presented. I hope your server is secure and users happy.
Be warned though that code should always be audited, it just takes 1 programming slip up to undo all of this, and although this should protect against most attacks, it is by no means 100% full proof.
Remeber to always check your logs read every log you can, and investigate any errors or warnings that arise, either warn the user/developer that it belongs to or patch it yourself.
As always comments and likes are always welcomed, good luck administrating.

Sharing is caring!

Leave a Reply