Security with Apache htaccess Tutorial
Apache Security tips and tricks for securing Apache Web Servers using htaccess, httpd.conf, and other built-in techniques to thwart attackers. This really should be required reading for any Apache admin or user because these little tricks are so easy to do.
« Apache Authentication in htaccess | .htaccess Tutorial Index | » SSL example usage in htaccess
Security with Apache htaccess
- CHMOD your files
- Prevent access to .htaccess and .htpasswd files
- Show Source Code instead of executing
- Securing directories: Remove the ability to execute scripts
- ErrorDocuments
CHMOD your files
Chmod your .htpasswd files 640, .htaccess files 644. Chmod php files 600, chmod files that you really dont want people to see as 400 (wp-config.php, config.php) and NEVER chmod 777, if something requires write access use 766 first then 775
Prevent access to .htaccess and .htpasswd files
You will almost never have to do this unless you are working with your config file for the whole server. Anyway its easy to test if you need this.
<Files ~ "^.ht"> Order allow,deny Deny from all </Files>
Show Source Code instead of executing
If you'd rather have .pl, .py, or .cgi files displayed in the browser as source rather than be executed as scripts
RemoveHandler cgi-script .pl .py .cgi
Securing directories: Remove the ability to execute scripts
This is cool, you are basically categorizing all files that end in certain extensions so that they fall under the jurisdiction of the -ExecCGI
command, which also means -FollowSymLinks
. And the opposite is also true, +ExecCGI
also turns on +FollowSymLinks
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi Options -ExecCGI
ErrorDocuments in htaccess
Note: 401 Errors only redirect to a local file, not an external file. Also, When you use an external link, don't do an external link to your site or you will cause a loop that will hurt your SEO.
Article: ErrorDocument Info and Examples, HTTP Status Codes
Common STATUS Codes and ErrorDocument Implementations
NOTE:
You will most definately want to check out and use the Google 404 Error Page.
#BAD_REQUEST ErrorDocument 400 /cgi-bin/e400.php #UNAUTHORIZED ErrorDocument 401 /cgi-bin/e401.php #FORBIDDEN ErrorDocument 403 /cgi-bin/e403.php #NOT_FOUND ErrorDocument 404 /cgi-bin/e404.php #METHOD_NOT_ALLOWED ErrorDocument 405 /cgi-bin/e405.php #REQUEST_TIME_OUT ErrorDocument 408 /cgi-bin/e408.php #GONE ErrorDocument 410 /cgi-bin/e410.php #LENGTH_REQUIRED ErrorDocument 411 /cgi-bin/e411.php #PRECONDITION_FAILED ErrorDocument 412 /cgi-bin/e412.php #REQUEST_ENTITY_TOO_LARGE ErrorDocument 413 /cgi-bin/e413.php #REQUEST_URI_TOO_LARGE ErrorDocument 414 /cgi-bin/e414.php #UNSUPPORTED_MEDIA_TYPE ErrorDocument 415 /cgi-bin/e415.php #INTERNAL_SERVER_ERROR ErrorDocument 500 /cgi-bin/e500.php #NOT_IMPLEMENTED ErrorDocument 501 /cgi-bin/e501.php #BAD_GATEWAY ErrorDocument 502 /cgi-bin/e502.php #SERVICE_UNAVAILABLE ErrorDocument 503 /cgi-bin/e503.php #VARIANT_ALSO_VARIES ErrorDocument 506 /cgi-bin/e506.php
When using CGI PHP, php 404 Error example
You may also have to send a "Status" header in addition to the HTTP 1/1 header.
<?php ob_start(); header('HTTP/1.1 404 Not Found'); header('Status: 404 Not Found'); ?> Error message
An example 404 Error page in perl cgi
#!/usr/local/bin/perl print "Status: 503 Service Temporarily Unavailablen"; print "Content-Type: text/html; charset=UTF-8;n"; print "Retry-After: 3600rnrn"; print " <!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"> n <html> <head>n <title>503 Service Temporarily Unavailable</title> n print " </head> <body> n <h1>Service Temporarily Unavailable</h1> n <p>The server is temporarily unable to service yourn"; print "request due to maintenance downtime or capacitynproblems. Please try again later.</p> n </body> </html> ";
ErrorDocuments generated by Apache
Have a top.html
<!--#if expr="! $CONTENT_LANGUAGE" --> <!--#set var="CONTENT_LANGUAGE" value="en" --> <!--#endif --> <!--#if expr="! $CHARACTER_ENCODING" --> <!--#set var="CHARACTER_ENCODING" value="ISO-8859-1" --> <!--#endif --> <?xml version="1.0" encoding="<!--#echo var="CHARACTER_ENCODING" -->"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="<!--#echo var="CONTENT_LANGUAGE" --> " xml:lang=" <!--#echo var="CONTENT_LANGUAGE" --> "> <head> <title> <!--#echo encoding="none" var="TITLE" --> </title> <link rev="made" href="mailto:<!--#echo encoding="url" var="SERVER_ADMIN" --> " /> <style type="text/css"> <!--/*--><![CDATA[/*><!--*/ body { color: #000000; background-color: #FFFFFF; } a:link { color: #0000CC; } p, address {margin-left: 3em;} span {font-size: smaller;} /*]]>*/--> </style> </head><body> <h1> <!--#echo encoding="none" var="TITLE" --> </h1> <p>
bottom.html
</p> <p> <!--#include virtual="../contact.html.var" --> </p> <h2>Error <!--#echo encoding="none" var="REDIRECT_STATUS" --> </h2> <address> <a href="https://www.askapache.com/"> <!--#echo var="SERVER_NAME" --> </a><br /> <!--#config timefmt="%c" --> <span> <!--#echo var="DATE_LOCAL" --> <br /> <!--#echo var="SERVER_SOFTWARE" --> </span> </address> </body> </html>
New
errordocument 401 /error/401.html AuthType Basic AuthName "site" AuthUserFile /path/to/.htpasswd AuthGroupFile /dev/null Require valid-user SetEnvIf Request_URI "^/(error/401.html¦robots.txt)$" allow_all Order allow,deny Allow from env=allow_all Satisfy any
Mod_python Security Considerations
Many of the same security issues that apply to other embedded interpreters apply to mod_python. Here are some brief descriptions. Rather than list the solutions in detail, use them as a basis to search the mailing list or web:
Store sensitive data in modules outside of the DocumentRoot of your site. This prevents modules from being exposed if mod_python isn't running.
Because the embedded interpreter runs applications as the apache user, all other applications may have access to the same files. This can have serious implications in a multiuser environment, and applies to PHP, SSI, CGI, etc., as well.
Avoid any kind of dependency on the PATH environment variable. It can easily be changed by other applications, causing your own to fail. If you must call system programs, declare the full path explicitly, always.
Debugging information can be essential when developing an application. Take pains to ensure that error messages don't reveal sensitive data if they are returned to the browser. Review your code, and use try/except statements to catch errors when appropriate.
Learn about Python's mechanisms to restrict what gets exported by a module.
If your database and application are on the same machine, don't let the database listen on a port exposed to the Internet.
Understand the quirks of mod_python.publisher if you use it as a handler. For example, add a leading underscore to objects if you do not want them to be directly accessible via HTTP. (4)
_fo = "secret password"
If using mod_python.publisher and the legacy importer PythonOption mod_python. (or mod_python version < 3.3), don't use the same name for Python code files (module names) in multiple places. This is because there are bugs in its implementation which can cause cross contamination of modules, the loading of the wrong module and other issues. See: MODPYTHON-9MODPYTHON-10MODPYTHON-11
If you use PythonAutoReload, realise that modules are simply reloaded on top of the already loaded modules. This is in part shown in the MODPYTHON-11 bug report. It is mentioned here as a separate item because it means that if you rename a variable/function or remove it, that doesn't actually mean it is no longer accessible. The only way to guarantee that old variables/functions are no longer accessible is to restart Apache. Thus, if you heed (4) and rename variables to have a leading underscore, make sure you restart Apache at the same time.
If multiple people share the same web server, use PythonInterpreter to assign your area of the web site its own instance of the Python interpreter. This isn't fool proof as another user could do the same thing and use the same name. When working though, it will keep your stuff separate from others and avoid them being able to more easily see and fiddle with the internals of your running application.
When using the mod_python.psp handler with PythonDebug On the source code for your PSP pages can be visible by virtue of putting an underscore on the end of the extension. You need to add the .psp_ extension to your AddHandler configuration directive to turn on this feature.
AddHandler mod_python .psp .psp_ PythonHandler mod_python.psp PythonDebug On
It is thus a good idea not to have PythonDebug enabled for production and/or public web site if using mod_python.psp. If you really need PythonDebug to be on, only enable it for requests coming from your own client machine in some way.
If Apache has write access to directories, it can write .pyc files into the directories for modules loaded. This extension isn't generally protected and people can download the ".pyc" files and potentially work out what your code is. Use something like:
<Files *.pyc> deny from all </Files>
Depending on platform, you may have to block access to .pyo files as well.
<Files *.pyo> deny from all </Files>
Use the FilesMatch directive to disallow access to important types of files, such as *.pyc, *.pyo, *~, etc.
Turn off automatic directory indexing for Apache on directories which use mod_python. This is generally applicable to any web site, but potentially more so for mod_python if you forget to do (3). Thus don't use "Indexes" option.
If using an extension such as ".html" with AddHandler to map to handler code in actual directory, ensure you block access to ".py" extension if need be.
<Files *.py> deny from all </Files>
Don't store backup files where they can be accessed via HTTP. Honestly, I'm sure I could gather about a thousand database passwords in a day if I simply created a bot that crawled dynamically driven sites and appended ~ to every file name it finds.
PythonDebug in general can reveal stack traces to a client when something goes wrong. In the worst case, this may reveal secret information.
Try to avoid putting source code in actual directories visible to Apache. Especially do not put sensitive information in such files. The reason here is that it only takes one mistake in Apache configuration and all your code would be visible.
When writing a custom handler and returning apache.DECLINED, make sure you understand what it does. Specifically, it will cause the builtin default Apache handler to still run, which will serve up static files. Like above, you may need to deny access to certain files as a result.
External Apache htaccess security Articles
htaccess Guide Sections
- htaccess tricks for Webmasters
- HTTP Header control with htaccess
- PHP on Apache tips and tricks
- SEO Redirects without mod_rewrite
- mod_rewrite examples, tips, and tricks
- HTTP Caching and Site Speedups
- Authentication on Apache
- htaccess Security Tricks and Tips
- SSL tips and examples
- Variable Fun (mod_env) Section
- .htaccess Security with MOD_SECURITY
- SetEnvIf and SetEnvIfNoCase Examples
« Apache Authentication in htaccess | .htaccess Tutorial Index | » SSL example usage in htaccess
« Apache Authentication in htaccesshtaccess HTTPS / SSL Tips, Tricks, and Hacks »
Comments