Installing and maintaining a secure web server on Linux can be a challenge. It requires in-depth knowledge of Linux, Apache, and PHP server-side options. One of the main problems is to find the balance between security and productivity and usability. The best solution depends on the specific project requirements, but all installations share certain common characteristics. Here are some best practices for securing a LAMP server, from the server configuration to fine-tuning PHP settings.
The task of securing a web server should begin with hardening the Linux operating system. Hardening Linux could be a whole article of its own, but certain concepts are especially important in regards to serving web content:
- Linux kernel hardening The kernel is the most frequent target for attackers. Having access to the kernel is the easiest way to escalate users’ privileges. Depending on the operating system, Apache runs by default as the limited user nobody (on Red Hat-based distributions such as CentOS) or www-data (on Debian-based distros, including Ubuntu). Every attacker’s aim is to break out of the limited user and gain root access by exploiting a vulnerability in the kernel. Patching your kernel with grsecurity ensures that you stay protected even against zero-day vulnerabilities. In addition, Ksplice ensures that you apply all kernel updates on time to minimize security risks.
- Mandatory Access Control (MAC) Under a common web server deployment a regular user does not need access to compilers (gcc), system configuration files, or utilities like
find. Red Hat-based distros can use MAC policy software called SELinux; Ubuntu admins can turn to the similar AppArmor. While these MAC tools differ in features, they can each help you limit attackers’ actions. On the negative side, improperly configured MAC tools can impair the functionality of your web server. That’s why all MAC tools have non-enforcing modes that allow you to track false positives and reconfigure them for your specific environment. Still, if you find MAC tools too complex, you can simply change the permissions of some executables to 700 and allow only root to use them.
- Firewall You must restrict both incoming and outgoing traffic in order to prevent malicious connections to and from the server. Securing incoming traffic is a common practice for any kind of server. However, for web servers it is especially important to restrict outgoing connections in order to limit the effect of malicious scripts executed locally. The most reliable way to do this is by setting the default iptables chains’ policies to DROP. After that you explicitly allow the incoming and outgoing connections that are needed. However, you have to be careful when you restrict outgoing traffic, because many web scripts require external resources (RSS, external APIs). If you don’t feel comfortable with the iptables firewall tool, you can use scripts to help generate and maintain the necessary firewall rules, such as Shorewall and Firestarter.
Apache Best Security Practices
Once you’ve secured the Linux operating system you can begin to take care of the Apache web server. The following instructions are specifically for Apache but may also apply for other web servers, such as LiteSpeed and nginx. Very often differences between them are just in the names of the modules or the configuration directives.
To harden Apache go through these steps:
- Install mod_security, an Apache module that works as application firewall. It filters all parts of a web request and stops malicious code. It works before any actual processing by the web server and thus is web application-independent. Mod_security is good for filtering anything from SQL injections to XSS attacks. It is the fastest and easiest way to protect a vulnerable web application. The software has various ready-to-use rules publicly available, but you can also write your own easily. Imagine for example that you have an outdated version of Joomla and you are worried about SQL injection attacks. This simple rule filters any POST and GET content containing jos_ (the default Joomla tables’ prefix):
- Install mod_evasive, another important Apache module that protects web applications against denial of service (DOS) requests. Its effectiveness is limited by the fact that it works on the application level, meaning Apache accepts the connections anyway, thus consuming bandwidth and system resources. Still, it can help in cases of weaker DOS attacks that originate from a small number of remote hosts. Once mod_evasive is loaded you might configure it thusly:
DOSPageCount 2 DOSSiteCount 30 DOSBlockingPeriod 120
This instructs the server to block (return HTTP error 403 Forbidden by default) any host that hits the same page twice or has a total of 30 requests within one second (the default time interval). The intruder will be blocked for 120 seconds.
- Filter visitors’ IP addresses. This might be considered drastic action but it is very effective. First, consider installing mod_httpbl, an Apache implementation for Project Honeypot. Once installed and enabled it blocks IP addresses that have a proven record of malicious activities. Another option is to use mod_geoip, which can be used to allow visitors from only certain countries to pages that accept input such comments, registration, and login information. It can even block and allow server-wide visitors from certain countries.
Other recommended Apache options include setting a low
Timeoutoption, such as 15 seconds. This limits the effect of DOS attacks by lowering the time the web server waits for certain events. A good source for further reading is the official Apache documentation and its security tips.
PHP is the most popular server-side language in the open source world. The fact that it is server-side means you need to set clear rules and limitations for its access to server resources via directives such as memory_limit, execution_timeout, and disable_functions. However, PHP configuration directives can be defined and redefined in various places, as explained here. Make sure that you are aware of the scope of these settings when enforcing them globally.
If you have the latest version of PHP installed with its default settings, your environment is already up to some decent security standard. Dangerous options such as register_globals and allow_url_include have been disabled by default. Still, this is not enough. One of the most important options to consider tweaking is
disable_functions, which, as its name suggests, disables PHP functions. Here is an example of how to prevent dangerous shell code executions:
There have been many attempts to bring additional security to PHP, both from inside and outside its development team. One unsuccessful attempt was PHP’s Safe Mode, the main idea of which was to restrict files’ access depending on their owners. This feature proved to be incorrectly designed and has been deprecated since PHP 5.3. However, an external security project called Suhosin has proven its worthiness. It is bundled with PHP in popular Debian-based distributions.
Suhosin can be installed in two ways. One is by patching the original PHP source code before the actual PHP compilation. This method is recommended because it makes Suhosin an integrated part of PHP, allowing Suhosin to protect the PHP core through its Engine protection features. The second option, which is easier, is by adding it as a regular PHP extension. Suhosin’s extensive features apply to many security aspects, such as session data encryption, request payload limits, and even, as an experimental feature, SQL injections prevention.
By default PHP runs as an Apache module under the Apache user, which ensures the best performance and compatibility with applications’ requirements. However, if a site has more than one vhost it could cause serious security problems, especially if vhosts belong to different users. In such cases a script from one vhost may be able to read, write, and execute scripts from other vhosts, which compromises security, not to mention privacy.
To mitigate this you can use another Apache module, called mod_suphp, which allows PHP scripts to run under a predefined user. Such a module is a must for shared hosting servers. With mod_suphp in place scripts from one vhost cannot even read files from other vhosts, let alone write to them. Disallowing reading of foreign vhosts’ files is essential for configuration files, which is why such files must have permissions of 600. Without that, your database details could be easily discovered, and that’s the least of the trouble you could find yourself in.
In mod_suphp’s configuration file (by default /etc/suphp.conf) you can enforce global safe files’ permissions policies with the options
allow_directory_others_writeable. Under normal circumstances all of them should be defined as false. Executing scripts that do not obey these restrictions produces an HTTP Error 500 Internal server error.
When securing a web server, also consider the following:
- Separate different web applications on the same server onto vhosts and run them with different users.
- Install SSL when sensitive information such as passwords or credit card information is transferred. You can protect administrative panels with free, self-generated, non-commercial certificates.
- Don’t rely on only one method for admin access restriction. A large number of web exploits circumvent admin login requirements. Such threats can be mitigated by limiting access to the admin area by remote IP addresses, and changing the default admin URL or its port.
- Conduct regular security audits of the server.
- Subscribe to security newsgroups about the web services and applications you have deployed.
All of the information above serves as a road map for keeping a web server secure. Doing the job right requires a lot of time and effort. If you’re not prepared to invest that time, you might be better off using shared hosting or fully managed servers.