10 straightforward but proven ways to harden your LAMP servers

Over the years I have had to harden a great number of LAMP boxes, I have found some methods work for better than others. I will now share with you all my favorite 10 along with methods to implement them on Debian/Ubuntu.

10. Lock SSH access right down. I do this by disabling root logins, disabling password authentication and using denyhosts.

To disable root logins do this: vi /etc/ssh/sshd_config and look for the following line: PermitRootLogin yes and change it thus: PermitRootLogin no

To disable password authentication (you will have to use public/private keys) do this: vi /etc/ssh/sshd_config and look for the following line: #PasswordAuthentication yes (note its commented out) and change it thus: PasswordAuthentication no

To install denyhosts do this: apt-get install denyhosts once installed it shouldn't need any configuration, but you can tweak the settings if you wish in /etc/denyhosts.conf

9. Always use Sudo for root access, This is one of the things Ubuntu does really well and its about time other distros did the same.

Before you disable the root account you need to make sure you have sudo access like this: visudo and then add a line like this (substituting username for your actual username): username ALL=(ALL) ALL

With that done you can lock the root account passwd -l root

8. If your using PHP in your LAMP stack then use Suhosin. It does break some code - but that's a good thing - it breaks bad code

To install it do the following apt-get install php5-suhosin then make sure its enabled: vi /etc/php5/conf.d/suhosin.ini that file should contain this line extension=suhosin.so if it doesn't put it in.

7. Secure MySQL by only allowing root logins from a few management systems and not from localhost.

This one sounds a bit strange, but by doing this it makes it very hard for someone to root your mysql if all they have is a user account on your LAMP server (hopefully some of you can see the logic here).

Say for example all your admins sit behind a NAT box that has the ip 123.123.123.123 then the commands for mysql to lock it down would be like this: update user set host = '123.123.123.123' where user="root"; that will leave the root passwords intact and only allow logins from a single management IP, but NOT localhost.

6. If for whatever reason you can't install Suhosin then make all traffic to port 80 and 443 go through a Squid that by default denies everything. You would be amazed how easy it is to stop XSS using this method – yet virtually no one does it.

To install squid (even on the localhost is better than not at all) do this: apt-get install squid3

Once it is installed you will need to completely wipe out its config: echo "" > /etc/squid/squid.conf

Here is my config (it blocks everything but allows me to grab anything from finance.yahoo.com, anything from urls in the http://apt.sw.be/redhat/el5/en/ hierarchy and anything from the single ip 123.123.123.123 )

http_port 3128 transparent
acl lamp src 127.0.0.1/32
acl lamp_allow dstdomain finance.yahoo.com
acl lamp_allowurl url_regex -i ^http://apt.sw.be/redhat/el5/en/
acl lamp_allowip dst 123.123.123.123/255.255.255.255
http_access allow lamp lamp_allow
http_access allow lamp lamp_allowip
http_access allow lamp lamp_allowurl
http_access deny lamp

Once you have that in place you need to setup iptables to transparently pass everything through the proxy $FW --table nat -A OUTPUT --proto tcp --destination ! localhost --destination-port 80 -j DNAT --to-destination 127.0.0.1:3128 this snippet relies entirely on the firewall script I have coming next.

5. Firewall yourself off from the rest of the world, Unless you totally have to only run a webserver on your webserver this makes firewalling very simple.

#!/bin/sh
#
#
# firewall by l2admin
#
# description: Firewall startup script
#

MANAGEMENT_HOSTS=”123.123.123.123/32″

FW=/sbin/iptables

#
# Make sure the user is SETUID root
#
if [ $UID -ne 0 ];
then
echo “You must be root to run this.”
exit 1
fi

case “$1″ in
start)
echo -n “Starting the firewall: ”

#
# Flush all rules
#
$FW -F

### INPUT

# base case
$FW -P INPUT DROP
$FW -A INPUT -m state –state INVALID -j DROP
$FW -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT
$FW -A INPUT -p tcp –tcp-flags SYN SYN –tcp-option \! 2 -j DROP

# localnet
$FW -A INPUT –in-interface lo -j ACCEPT

# ICMP

$FW -A INPUT -p icmp -j ACCEPT

# SSH, SNMP, NAGIOS
for I in $MANAGEMENT_HOSTS
do
$FW -A INPUT –source $i -p udp -m udp –dport 123 -j ACCEPT
$FW -A INPUT –source $i -p udp -m udp –dport 161 -j ACCEPT
$FW -A INPUT –source $i -p tcp -m tcp –dport 22 -j ACCEPT
$FW -A INPUT –source $i -p tcp -m tcp –dport 5666 -j ACCEPT
done

# HTTP
$FW -A INPUT -p tcp -m tcp –dport 80 -j ACCEPT
$FW -A INPUT -p tcp -m tcp –dport 443 -j ACCEPT

# Squid proxy transparent redirect rule
$FW –table nat -A OUTPUT –proto tcp –destination ! localhost –destination-port 80 -j DNAT –to-destination 127.0.0.1:3128

# reject (what to do with anything not allowed earlier)
$FW -A INPUT -p tcp -j REJECT –reject-with tcp-reset
$FW -A INPUT -j REJECT –reject-with icmp-port-unreachable

### OUTPUT
# base case
$FW -P OUTPUT DROP
$FW -A OUTPUT -m state –state INVALID -j DROP
$FW -A OUTPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

# allow
$FW -A OUTPUT -j ACCEPT #allow everything out

# reject (what to do with anything not allowed earlier)
$FW -A OUTPUT -p tcp -j REJECT –reject-with tcp-reset
$FW -A OUTPUT -j REJECT –reject-with icmp-port-unreachable
echo “done”
;;
stop)
echo -n “Stopping the firewall: ”

$FW -F
$FW -F -t nat
$FW -A INPUT –jump ACCEPT
$FW -A OUTPUT –jump ACCEPT
$FW -A FORWARD –jump ACCEPT
$FW -X

echo “done”
;;
restart)
$0 stop
$0 start
;;
status)
echo “”
echo “Firewall Rules”
echo “————–”
echo “”
echo “”
echo “MAIN RULES”
echo “”
$FW -L -n

;;
*)
echo “Usage: firewall {start|stop|restart|status}”
exit 1
esac
exit 0

Save this as /etc/init.d/firewall and start it.

4. Where you can install your webapps from apt, I know that the code may be somewhat older but it will setup apache/php/mysql for you – usually with very sane defaults. And when a bug is found (and one will be) then item 2 will tell you its time to update ;-)

3. Sign up for an account with someone like trust-guard, I have used their services extensively over the years and while they are not free they are very good, and if you only want to scan your server once then they are free – if its for a commercial site then its worth paying for. The key thing with services like these is if you get reports saying you have problems don’t ignore them!

2. Keep everything up to date, it is very rare for any serious bugs to get introduced into security patches and when they do they are fixed lightning fast. Again like the external scanning systems, if you get an email saying something needs an update don’t put it off!

First you need cron-apt: apt-get install cron-apt
Then edit /etc/cron-apt/config set your email address by changing (root is the default) MAILTO=""

By default cron-apt will run daily at 4am, but you can change that by editing /etc/cron.d/cron-apt

1. I work for a commercial web host so sadly we can't avoid doing this, but if you don't and you are running your own LAMP boxes then it should be easier - my last tip is this - don’t let n00bs on your server. The havoc caused by someone random installing some unheard of bit of PHP can be quite epic. As a side note to this if you can avoid things like joomla do, we have over 25,000 installs and climbing daily and virtually every one is vulnerable to something or another, but I eat my own dog food and follow items 10 – 2 and we have no issues with them.

If it wasn't for poorly coded web apps (and its not actually joomla thats at fault but 9/10 the add-in authors) then we wouldn't need a lot of the protection I have shown you here how to put in place.

[ Article saved from l2admin.com, which has since disappeared from the Internet ]