Learn Best Practices for Web Server Security
In this, the first of two articles, we will talk about securing the overall hosting environment, PHP (surprise), and file system permissions. Many people will try to sell you an "application firewall" or similar devices, but I tend to believe that's too reactive, and not enough of a proactive approach to security. Every little bit helps in security, but adding layers without addressing the underlying problem is asking for trouble.
The Environment We Must Live With
In the world of Unix, especially Linux, we must hold to some truths. There are specific file system permissions required for certain things to happen, we must allow some level of access to users' scripts and PHP applications, and we cannot lock things down as tightly as we'd like. I can create and thoroughly secure a Web server hosting static content, but how useful is that? The most secure Linux box is disconnected from the network, but again, it is not very useful. Somewhere, in between multiple extremes, there is a workable medium.
We aren't talking about a happy medium, notice. There is no happy medium in security. Keeping any platform secure is an iterative process, which involves multiple layers of security and constant maintenance.
Many companies, at least a few I've seen recently, have widely varying ideas about how to configure permissions for Web hosting users. The two basic schools of thought are: give every user their own group and a umask of 002, or require that the user maintain their own permissions, with a 022 umask.
In the first scenario, the benefit is that when collaborating, users never need to mess with permissions. Their umask will cause files to be written with group writable permissions, which is OK, because context matters. If they are writing files to a shared group resource, the parent directory will have the setgid bit set, and all files will be created with the same group id. Likewise, if they are in their own space, files will be written with the user's own group id. There are no obvious security holes here, but two issues quickly come to mind. First, this is training the user of the system to not pay attention to permissions at all. Second, certain security settings and third-party modules will not operate if files are group-writable, because the potential exists for malicious code to be introduced. If a single user's account in a group is compromised, the shared storage is as well.
The second scenario doesn't train users to ignore permissions, and allows modules like su_exec to run without hacking the source and commenting out the code that checks for group-writable files. In the end, the biggest concern regardless of the strategy to deal with collaboration among users, is that users will continue creating world-writable directories.
Many Web applications, even popular ones, tell the user to 'chmod 777' as part of the install process. That's fine, but they never tell them to fix the permissions after the installation process! Increasingly, especially in the .edu world, I've seen more and more malicious scripts actively looking for world-writable directories. A compromise of a single site on a server often leads to many sites having unauthorized content written to them.
Of course, we cannot talk about Web security without mentioning PHP, the bane of Web hosting.
PHP scripts are generally interpreted via the mod_php Apache module. This means that PHP scripts written by a user will run as the Web server user. This standard configuration causes many issues with file permissions. What if a Web developer wants to connect to a database? They must provide a password, and the file containing the password must be readable by the Web server. Since the Web server runs all scripts as the same user (it's running PHP itself), all users on the system can access this information via their own PHP scripts. There must be a better way.
And indeed, if you're running mod_suexec, you can execute CGI programs as the user that owns them. Apache will run a program as root, which detects what user it should switch to based on the owner, and then runs the CGI as that user. PHP on the other hand, cannot be done this way, unless you're running Apache as root (don't). The workaround, since suphp doesn't really work, is to run all PHP applications as a CGI program. There's quite a performance hit, but the benefits provided by running PHP applications as the user that owns then far outweigh the performance concerns—buy more servers and be done with it.
With user-run PHP scripts, you can easily identify which user's application is at fault when someone has executed a script that spams or launches a DoS attack.
This is one step closer to managing the problem, but we're still not doing anything about the initial attack vector. Two problems exist: insecure PHP settings, and insecure applications. The entire next article will be devoted to insecure applications.
PHP settings are tricky. Most downloadable applications, especially the popular blogs or CMSes, will break if you reign in PHP too tightly. Setting safe_mode, for example, will break most PHP. Dallas Kashuba of Dreamhost was kind enough to share with me some PHP settings they use for the few customers that use mod_php. The set of most dangerous PHP functions, ones that should be disabled, are:
One final note: an extremely useful module available for Apache is mod_security. Very much like an application firewall device does, mod_security will inspect every transaction and compare it to a list of possible attacks. The rules by which it blocks exploits must be constantly updated, but it's certainly worth the care and feeding.
It's all about minimizing the likelihood of break-ins, and then minimizing the impact they can have. There are many more aspects to securing a server in a multi-user environment, which I briefly wrote about previously in, "Keeping a Lid on Linux Logins." Carla Schroder also introduces SELinux, in "Tips For Taming SELinux."
As much as we'd like to prevent security incidents in the Web hosting world, we have come to face the reality that they will happen. Come back next week to learn about managing the major problem: the applications themselves.