I've stopped maintaining the page for nginx because it hasn't received many views since I updated it about six months ago. I suspect that nginx on OpenBSD is not all that popular because the
httpd that ships with OpenBSD provides almost the same functionality as a
basic installation of nginx. The pages for httpd in base and Apache2 now cover PHP7 and both configurations appear to work really well.
PHP/MySQL on OpenBSD's relayd-based httpd
HiR's Secure OpenBSD/Apache/MySQL/PHP Guide
Feel free to comment on this post if you find any discrepancies or have suggestions. Comments are disabled on the walk-through pages.
(2017-04-23) Edited to add: I went ahead and re-worked the nginx guide, based on the httpd guide with new formatting.
PHP/MySQL with nginx on OpenBSD
2017-04-15
PHP/MySQL Walk-Throughs updated for OpenBSD 6.1
2015-06-14
OpenBSD PHP/MySQL Walk-throughs are up to date (Finally!)
First and foremost, I finally took the time to wrap my brain around OpenBSD's new relayd-based httpd. You can see the walk-through here:
While I was at it, I refreshed the guides for nginx and apache.
These should be maintained for future versions of OpenBSD going forward. Enjoy!
2012-11-03
Introducing: nginx/MySQL/PHP stack on OpenBSD
While our walk-through for Apache/MySQL/PHP on OpenBSD is quite popular, the upgrade documentation for OpenBSD 5.2 is quoted thus:
nginx (see also nginx(8)) has been added to OpenBSD, ultimately to replace the Apache 1.3 derived httpd(8). For new installations, you are encouraged to utilize nginx rather than httpd, existing installations are encouraged to start planning replacing the stock httpd with nginx.
With Apache 1.3 being awfully long in the tooth, most of us saw something like this coming. With that, there's a new walk-through that covers the basic configuration of nginx, MySQL and php-fpm to create a working, secure and chroot-enabled web application environment in OpenBSD 5.2.
Introducing: The OpenBSD nginx/MySQL/PHP stack
2012-05-07
OpenBSD 5.1 Released: OAMP Updated
OpenBSD 5.1 was released last week, so the update is a bit overdue. HiR's Secure OpenBSD + AMP guide has been updated. OpenBSD 4.x is officially unsupported now, so we've dropped the 4.x parts from the guide and refined the rest. Since we've started covering the setup of an AMP stack on OpenBSD, the process has gotten considerably easier. OpenBSD is a completely viable and stable environment for running almost any PHP/MySQL web app, with a little extra consideration given to the chroot environment and Suhosin hardening patches while you're setting up your applications or programming new ones.
2011-11-12
OpenBSD 5.0: Apache, PHP and MySQL
The basic steps for taking a bare-bones install of OpenBSD and adding an AMP stack for web applications hadn't changed much in the past 2 years. Although 5.0 is not seen as a "major update", but simply a continuation of the normal development cycle, the OpenBSD team did a few things that make the installation a bit different this go around. I'll cover some of the recent changes to OpenBSD and its packages in this post, then you can dive right into the updated OpenBSD Chroot Apache, PHP, MySQL setup guide.
Initialization scripts: Starting with OpenBSD 4.9, the RC scripts became modular. This is similar to how NetBSD and FreeBSD have worked for many years. Individual daemons have startup scripts in /etc/rc.d, but rc.conf, rc.local and rc.conf.local still work the same, so it wouldn't surprise me if many OpenBSD users didn't even notice the change. It seems like OpenBSD 5.0 packages for most of the popular services (samba, cups, postgres, etc) are actually creating these startup scripts now. If a third-party application from packages installs a startup script in /etc/rc.d, you can add it to the pkg_scripts variable in /etc/rc.conf.local like so, and it'll magically start.
pkg_scripts="mysqld cups samba"
See the OpenBSD man page for rc.d for more details.
MySQL and chroot: I'm not sure why it didn't dawn on me before, but one really simple way around hard-linking MySQL's socket file into the chroot environment is to simply have your web applications connect to MySQL's TCP port on 127.0.0.1 (not localhost, because that means "use the socket file" in MySQL-ese) I think I'll be doing it this way in the future.
PHP: PHP 5.3 added a lot of features, such that PHP 5.2.x and PHP 5.3 might as well be different major version numbers when complex web applications are considered. OpenBSD 5.0 adds packages for PHP 5.3 for the first time, but PHP 5.2 is still available in the repository. For this reason, the PHP core and module packages are no longer prefixed by php5-, they're just php, php-mysql, etc. Since PHP 5.2 is still supported, the version numbers are used to distinguish them, like this:
$ sudo pkg_add php-mysql
Ambiguous: php-mysql could be php-mysql-5.2.17p3 php-mysql-5.3.6
Further, some configuration file locations have been changed. If you pay attention to the text after installing packages, this shouldn't make much difference. Hint: you can always re-read the post-install notes afterward by using pkg_info -M.
All in all, the recent changes to OpenBSD are welcome. Some of the things I outlined here are areas where OpenBSD had some catching up to do. They've managed to do a lot of proactive stuff in the realm of hardware support and (of course) security and encryption. This is still one of my favorite platforms to tinker with.
2010-10-18
OpenBSD 4.8 is almost here! Chroot Apache, MySQL and Suhosin Hardened PHP
I actually cheated a bit to make this article, if you can call busting my ass performing a "make package" for hundreds ports in OpenBSD-current and doing a bunch of Virtual Machine snapshot reversions "cheating." It was a major pain in the butt to do, but I won't have much free time when OpenBSD 4.8 actually ships, so here you have it.
My Chroot OAMP series of articles is pretty popular, especially since attacks against PHP web applications are on the rise and people are looking for ways to get a little extra security for their web hosting environments.
By default, OpenBSD ships with a specially patched and code-audited derivative of Apache web server. It has been engineered specifically to run in a chroot environment, which is to say that even if someone or something could make Apache run arbitrary code, it can only impact what's in the web directory. It can't readily harm or disrupt the rest of the system.
The version of PHP in OpenBSD's package repository has also been tweaked with the Suhosin Hardened-PHP patch, which can defend vulnerable PHP applications from certain kinds of malicious attacks.
A relatively current version of MySQL is also in the package repository. The configuration provided isn't too bad.
Getting the software installed is easy, but turning it into a functional and secure AMP environment can be a chore if you haven't done it before.
Preparation:
During the installation of OpenBSD, you are prompted to create a non-root user. This feature was introduced last year with OpenBSD 4.6, and is primarily to discourage the improper use of the root account. The user you create during installation will be automatically added to the wheel group, which grants permission to use the su command. I generally add the wheel group to sudo as well, by adding this line to /etc/sudoers (with the root user):
%wheel ALL=(ALL) SETENV: ALLIf you are currently logged in with your user-level account, you will need to log off and log in again in order to use sudo.Package management used to be one of the more annoying aspects of OpenBSD. In 2004, I even wrote my own scripts to wrangle the packages. They've gotten consistently better over the years, and with OpenBSD 4.8, they introduced yet another great feature: /etc/pkg.conf (manual page .) There are only a few options available for this file right now, but it allows you to set global options for the package tools instead of setting up and relying on the PKG_PATH environment variable. If you perform an FTP install, the installer should automatically add the FTP mirror you used to this file. If you installed from CD but would like to use an ftp mirror for pkg_add, you need to add an "installpath" line to /etc/pkg.conf, which may not exist yet.
installpath=ftp://ftp5.usa.openbsd.org/pub/OpenBSD/4.8/packages/i386Of course, you can pick whichever mirror you like. The OpenBSD project maintainers frown upon pointing direct downloads at the main ftp site. You can easily add local package repositories to this path.
Installing Packages
Installing php5-mysql and mysql-server will fetch all of the dependencies for OAMP. This process may take a while depending on your connection speed. There are several dependencies that will be installed, including php5-core and some perl modules.
sudo pkg_add php5-mysql mysql-serverNext, copy the PHP + MySQL sample files into placesudo cp /var/www/conf/modules.sample/php5.conf \Run the script to get the default MySQL database installed, start MySQL and set a MySQL root password./var/www/conf/modules/
sudo cp /var/www/conf/php5.sample/mysql.ini \/var/www/conf/php5/
At this point, both MySQL and PHP are installed and set up with a default configuration that will probably work fine for most applications.sudo /usr/local/bin/mysql_install_dbsudo /usr/local/share/mysql/mysql.server startsudo /usr/local/bin/mysqladmin \-u root password 'your-password'
Chroot Setup
In this version of OpenBSD, a chroot /tmp directory already exists with the proper permissions in /var/www, which simplifies setup of the chroot environment. All we're left to do is to reproduce the directory structure for the MySQL socket under /var/www.
sudo mkdir -p /var/www/var/run/mysql # -p creates subdirs as neededStart Apache and MySQL at bootSet apache to start on boot by editing /etc/rc.conf. Find the httpd_flags line in the file, change NO to "" -- literally, two double quotes as shown below.
Then, make sure that MySQL starts at boot and that the real mysql.sock file gets hard linked into the new directory by editing /etc/rc.local. I also added a line to remove the old hard link before starting MySQL. The end of my /etc/rc.local looks like this:# use -u to disable chroot, see httpd(8)httpd_flags=""
rm /var/www/var/run/mysql/mysql.sockAfter getting all of the services set up to start automatically, I usually reboot to make sure everything starts up as expected.
/usr/local/share/mysql/mysql.server starr
sleep 5
ln /var/run/mysql/mysql.sock /var/www/var/run/mysql/mysql.sock
sudo rebootTesting
Once the system comes back online, the most basic test of Apache and PHP is to create a phpinfo script. This can be done with one line of shell-fu, which will launch "tee" with root permissions to write the phpinfo.php file.
echo "<?php phpinfo(); ?>" | sudo tee /var/www/htdocs/phpinfo.phpThen, navigate to http://your.openbsd.ip.address/phpinfo.php in your web browser. It should load a nice-looking document containing details about PHP's configuration. In particular, check for MySQL.
To wrap up, I performed the usual "5 minute install" of Wordpress 3.0.1 (current as of writing) to see what happens. The end result was a totally painless and fully functional setup that's ready to go.
2010-05-17
OpenBSD 4.7 + Chrooted Apache, MySQL & Suhosin PHP
FYI - There's now a page that covers OAMP for all recent versions of OpenBSD. My OAMP series is a popular one. Although OpenBSD 4.7 doesn't come out for 2 more days, the media has already shipped to those who pre-ordered. And, as I mentioned previously, you'll want to get crack-a-lacking on those patches. As of the time of writing, there are already 4 patches to install for OpenBSD 4.7, which affect all architectures.
I'll spare you the verbosity. The installation procedure for getting OpenBSD, Chrooted Apache, MySQL and Suhosin-hardened PHP all working together hasn't changed one bit in OpenBSD 4.7. You can follow my instructions verbatim from the OAMP 4.6 Walk-Through, with one minor difference: make sure you change "4.6" to "4.7" when defining PKG_PATH in your .profile.
I was able to go from an empty virtual machine to a fully-functioning, chrooted install of WordPress in under 30 minutes just by following the instructions (and, of course, pointing the PKG_PATH to the packages on the media, not FTP, since the 4.7 branch hasn't hit the Internet yet)
Now that blogger has the ability to store "pages", I may eventually convert this article series to a living document. There are also some lazy shortcuts I take that kind of go against traditional OpenBSD methods (directly launching stuff from rc.local, editing rc.conf instead of making changes in rc.conf.local, etc) - I may get around to de-cruft-ifying this how-to at the same time. Otherwise: Enjoy!
2010-02-08
Wrapping insecure web apps with Apache
When dealing with a web service which for one reason or another cannot or should not be allowed on the web. Apache has several wonderful modules which allows the services to be wrapped and behave like a web app should (working SSL certificates, forced encryption, authentication ...)
In this article I will discuss and show some examples on how to create an authenticated reverse proxy with mod_authnz, mod_proxy,mod_rewrite and mod_security.
-=-=-=-=-=-=-=-ToC-=-=-=-=-=-=-=-
1. Prerequisites
2. Installation of Apache
3. Configuration of Apache
4. Configuration of mod_rewrite
5. Configuration of mod_proxy
6. Configuration of mod_authnz(optional)
7. Configuration of mod_security
8. Summary
9. Informative Resources
-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-
1. Prerequisites
In this example you will need:
- Ubuntu Linux
- LDAP compatible server with valid SSL certificate
- Apache2
- Wildcard ssl certificate or valid certificates for each service published
- Apache mod_rewrite
- Apache mod_proxy
- Apache mod_authnz
- Apache mod_security
Install Apache2 by any of your favorite package managers or at the prompt:
sudo apt-get install apache23. Configuration of Apache
Then create a new config file for each of your new relays.
Inside of the virtual host tag:
UseCanonicalName Off4. Configuration of mod_rewrite
LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
#incase you have a self signed certificate on the ldap server
LDAPVerifyServerCert offSSLEngine On
SSLCertificateFile /etc/apache2/ssl/generic/example.com.crt
SSLCertificateKeyFile /etc/apache2/ssl/generic/example.com.key
Servername weirdone_wrapped.example.com
CustomLog /var/log/apache2/access_log.relay-weird.vhost vcommon
(mod-rewrite is included with apache2)
To enable mod_rewrite:
a2enmod rewriteThen add the following virtual host entry to redirect http traffic:
5. Configuration of mod_proxyRewriteEngine On
#Force HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*) https://%{SERVER_NAME}/$1 [R,L]
First install additional mod_proxy:
sudo apt-get install libapache2-mod-proxy-htmlThen enable the modules:
a2enmod proxy proxy_connect proxy_html proxy_httpInsert the proxy section and commands into the SSL (port 443) vhost section:
6. Configuration of mod_authnz(optional)Order deny,allow ProxyPreserveHost On ProxyPass / http://weirdapp.example.com:50281/ ProxyPassReverse / http://weirdapp.example.com:50281/
First install mod_authnz:
apt-get install libapache2-mod-authnz-externalThen insert the following into the proxy block for ldap authentication of the connection:
AuthType Basic AuthBasicProvider ldap
AuthName "Please authenticate your connection using your network login."
#Some Ldap servers will reject un-encrypted simple authentication, plus this is
#just a good idea any way.
AuthLDAPURL "ldaps://1.2.3.4/?cn" SSL
AuthzLDAPAuthoritative on
AuthLDAPBindDN cn=authbot,ou=users,o=org
AuthLDAPBindPassword password
AuthLDAPRemoteUserAttribute uid
AuthLDAPRemoteUserIsDN on
AuthLDAPGroupAttributeIsDN on
AuthLDAPGroupAttribute member
Require ldap-group cn=Staff,ou=groups,o=org
Satisfy All
7. Configuration of mod_security
First install mod_security:
apt-get install libapache-mod-securityThen enable it:
a2enmod mod-securityMod_security is fairly tricky, I am using a default configuration but I am only logging errors and not preventing them. Configuration beyond this is outside the scope of this article.
Edit /etc/apache2/mods-available/mod_security.conf and use the configuration example in
"/usr/share/doc/mod-security-common/examples/" as a template.
If it proves to be too restrictive, you can switch the part which says:
SecRuleEngine On
to
SecRuleEngine DetectionOnly
8. Summary
So, after this is installed, Apache will listen to a static IP then relay a a website to the end user over SSL after authenticating the connection with an LDAP server. And if anything fishy happens it will be logged/(or blocked) with mod-security.
This is not a 100% silver bullet solution. Apache http authentication is generally a bad idea, especially over an unencrypted session. In this example it is partially mitigated with mod_rewrite but at this time Apache does not natively support any modern authentication technologies with hooks for LDAP or any other authentication service. If you have the opportunity to prevent the need to do this then make it so.
The best way is to do it right the first time and write into your web application (or specify in the RFQ) the correct security measures.
9. Informative Resources
Breach Security "Mod Security home page". (Accessed April 2009)
http://www.modsecurity.org
The Apache Software foundation. "Apache webserver website". (accessed Jan 2010)
http://httpd.apache.org/
See also :
Asmodian X's Securing php web applications:
http://www.h-i-r.net/2009/05/securing-php-web-applications.html
Ax0n's OAMP (Apache, Mysql, PHP on OpenBSD) Article:
http://www.h-i-r.net/2008/12/sysadmin-sunday-amp-on-openbsd-44.html
Asmodian X's Name based hosting mini-howto:
http://www.h-i-r.net/2008/10/sysadmin-sunday-apache-name-based.html
Asmodian X's Workbench - Suhosin :
http://www.h-i-r.net/2008/12/asmodians-workbench-suhosin-hardened.html
2009-12-29
From the comments: Apache + UserDir + Chroot on OpenBSD
In the comments on the OpenBSD 4.6 OAMP article, azhax and I hashed out how to get UserDir functioning in a chroot. I don't usually need UserDir, but it's a common configuration for multi-user systems such as those found at universities and ISPs. It's definitely worth covering.
#!/bin/sh#addwebdir.sh#syntax: addwebdir.sh [username]mkdir /var/www/users/$1chown $1 /var/www/users/$1ln -s /var/www/users/$1 ~$1/public_html
2009-10-28
OAMP: OpenBSD 4.6 + Chroot Apache + MySQL + PHP
Introduction
I'm combining the OAMP howto with chroot from the start this time because it's really the proper and secure thing to do. You can read more about how chroot works in my last article about it, but the premise is that chrooting Apache limits the amount of damage that can be caused by vulnerabilities in web applications. Keep in mind that we'll be accessing MySQL from within the chroot in this article, so all content within MySQL is potentially at risk if you're serving up SQLi-vulnerable content. The best things the average sysadmin can do to protect the server is to keep webapps and system patches up-to-date, and to perform periodic database dumps and system-wide backups.
I will walk through the commands here without showing the output they generate. You can reference my OAMP walk-through from OpenBSD 4.4 if you want to see example output, which should look similar for OpenBSD 4.6. The output shouldn't matter much, because I'll walk you through everything here.
Preparation
To start off, I make sure that a user-level admin account has access to run anything as root from sudo. Note: all the administrative commands in this post begin with "sudo" for a reason. To do this, I add my admin account to the wheel group. You can do this during the adduser process or with usermod, but if you created a non-root admin user during the OpenBSD 4.6 installation process, that user will be in the wheel group by default. All you need to do is add a sudo rule for the wheel group. It's commented out in /etc/sudoers.
$ su -
Password:
# visudo
... or use whatever editor you want on /etc/sudoers. Not recommended.
Find the line that grants access to the wheel group, and uncomment it. It's about 35-40 lines down in the default configuration. Optionally, there's a NOPASSWD version of the same, a few lines down. I don't recommend using this option on a production server, but it may make system management more friendly on your development servers and workstations.
%wheel ALL=(ALL) SETENV: ALL
-- or --
%wheel ALL=(ALL) NOPASSWD: SETENV: ALL
I also set up the path for pkg_add by adding these lines to my user-level account's .profile, then logging out and back in to reload the profile. I usually use an OpenBSD mirror, like ftp5.usa.openbsd.org instead of the main FTP site. You can also use any of the http mirrors in this path.
vi .profile
PKG_PATH=ftp://ftp5.usa.openbsd.org/pub/OpenBSD/4.6/packages/i386/
export PKG_PATHInstalling PackagesInstalling php5-mysql and mysql-server will fetch all of the dependencies for OAMP. This particular version of PHP comes pre-compiled with the suhosin hardened PHP patches in place, which is a nice touch! This process may take a while depending on your connection speed. There are eight or nine packages in total, including php5-core and some perl modules that MySQL depends on for its management tools.
sudo pkg_add php5-mysql mysql-serverNext, copy the PHP + MySQL sample files into placesudo cp /var/www/conf/modules.sample/php5.conf \Run the script to get the default MySQL database installed, start MySQL and set a MySQL root password./var/www/conf/modules/
sudo cp /var/www/conf/php5.sample/mysql.ini \/var/www/conf/php5/
At this point, both MySQL and PHP are installed and set up with a default configuration that will probably work fine for most applications.sudo /usr/local/bin/mysql_install_dbsudo /usr/local/share/mysql/mysql.server startsudo /usr/local/bin/mysqladmin \-u root password 'your-password'
Chroot Setup
Most AMP packages only need somewhere to store Session information and a way to get to the MySQL socket. Since the real /tmp contains information that is not needed for Apache, we'll just create a new tmp directory specifically for Apache within /var/www and make it world-writable with the "sticky bit" set (exactly like the real /tmp)
sudo mkdir /var/www/tmpNext, reproduce the directory structure for the MySQL socket under /var/www.
sudo chmod 1777 /var/www/tmp
sudo mkdir -p /var/www/var/run/mysql # -p creates subdirs as neededStart Apache and MySQL at bootSet apache to start on boot by editing /etc/rc.conf. Find the httpd_flags line in the file, change NO to "" -- literally, two double quotes as shown below.
Then, make sure that MySQL starts at boot and that the real mysql.sock file gets hard linked into the new directory by editing /etc/rc.local. I also added a line to remove the old hard link before starting MySQL. The end of my /etc/rc.local looks like this:# use -u to disable chroot, see httpd(8)httpd_flags=""-or-httpd_flags="-u" #disables chroot. You can if you want.
rm /var/www/var/run/mysql/mysql.sock
/usr/local/share/mysql/mysql.server start
ln /var/run/mysql/mysql.sock /var/www/var/run/mysql/mysql.sock
After getting all of the services set up to start automatically, I usually reboot to make sure everything starts up as expected.
sudo reboot
Testing
Once the system comes back online, the most basic test of Apache and PHP is to create a phpinfo script. This can be done with one line of shell-fu, which will launch "tee" with root permissions to write the phpinfo.php file.
echo "<?php phpinfo(); ?>" | sudo tee /var/www/htdocs/phpinfo.php
Then, navigate to http://your.openbsd.ip.address/phpinfo.php in your web browser. It should load a nice-looking document containing details about PHP's configuration. In particular, check for MySQL.
To really put our fresh chrooted OAMP installation through its paces, I downloaded the latest version of Wordpress, then followed the instructions using "the famous 5-minute install", which is way beyond the scope of this article. It's as simple as creating a database, setting up a privileged user for that database, editing a configuration file and copying wordpress into /var/www/htdocs (or a subdirectory) before accessing the control panel to finish up.
The wordpress install worked without changing anything from the instructions, and it's all running under chroot without any problems!
If you find that things are not working well with a particular AMP application, check file permissions, and copy or create hard links to files or directories that are needed. Example: sometimes you need a fake /etc/password file, some tools from /usr/bin or a /dev structure to be replicated within the chroot environment. Add these only as needed.
2009-05-03
Sysadmin Sunday: Updated OAMP: OpenBSD 4.5 Apache MySQL PHP
FYI - There's now a page that covers OAMP for all recent versions of OpenBSD.
I'll keep this quick and easy. You can just reference my OAMP walk-through from 4.4 if you want to see some more output, but otherwise you can simply run these commands:
# sets up the path for pkg_add (I usually add these lines to my .profile)
PKG_PATH=ftp://ftp.openbsd.org/pub/OpenBSD/4.5/packages/i386/
export PKG_PATH# Installing these two packages will fetch all the dependenciessudo pkg_add php5-mysql mysql-server# Copy the sample files into placesudo cp /var/www/conf/modules.sample/php5.conf \# Get MySQL started and the default database installed/var/www/conf/modules/
sudo cp /var/www/conf/php5.sample/mysql.ini \/var/www/conf/php5/
# Set apache to start on boot by editing /etc/rc.confsudo /usr/local/bin/mysql_install_dbsudo /usr/local/share/mysql/mysql.server startsudo /usr/local/bin/mysqladmin \-u root password 'your-password'
# Launch apache (unless you plan on rebooting when this is done)sudo vi /etc/rc.conf#(find httpd_flags once editing the file)# use -u to disable chroot, see httpd(8)
httpd_flags=""-or-httpd_flags="-u"
sudo httpd-or-sudo httpd -u# Set MySQL to start at bootThat's really all there is to it!sudo vi /etc/rc.local(add the following line to the end)/usr/local/share/mysql/mysql.server start
If you run httpd in its default chroot mode, it can be difficult to get some AMP packages running properly due to the location of the MySQL socket and the php configuration. If you run httpd -u, most PHP5-compatible packages should just work with minimal effort.
I have never actually installed Wordpress before, and I got it up and running on OAMP (without chroot) in about 3 minutes by following the Wordpress instructions.


Next Sysadmin Sunday, I'll hopefully cover the things you should be prepared to do in order to run AMP packages in OpenBSD's default chroot environment. I've done it before (whilst working at a startup in 2006) but I'm a bit rusty.
2009-05-01
Securing Php Web Applications
PHP is a popular server side scripting language, it's as simple or as complex as you want to make it. It is typically used along with Linux, Apache Web server and MySQL RDBMS. In most web applications the script acts on user provided information and returns processed data. To this end there are a number of simple steps you can take to help make your web application less vulnerable to exploitation by an unfriendly party.
This article is intended for beginning to intermediate web application programmers.
=======ToC=========
1. Introduction
2. Methods of input
3. Input data validation
4. Trusted processing
5. Database queries
6. Raising the bar
7. Informative resources
===================
1. Introduction
PHP is a HTML pre-processor, meaning that it reads a file before it is sent to the user and if it contains PHP script, it processes it and returns the document and the processed results to the user. There are many other technologies which do the same thing each with their benefits and flaws. The importance here is not to proclaim the benefits of PHP over the others but to show some good ideas of how to protect your applications from un-friendlies.
2. Methods of input
In PHP we can get information externally from the webserver itself ($_SERVER), Cookies ($_COOKIE), Get variables ($_GET), Post Variables ($_POST) . In addition PHP can internally connect to just about anything.
Example:
So when Joe, our end user goes to your website to check this weeks Fantasy Football scores on your website, he will login (sending login information using POST variables) to a script which then reads the login information and decides whether he can login. Then it returns a page with the result of his attempt and then either takes him to the next page or back to the login prompt. Once he is logged in, PHP sets a Cookie with a unique random session id. Every time a browser returns that cookie to a page, it knows that this session is good and belongs to Joe. Then Joe sorts his results page sending some criteria via a Get variable which is used to control a query to the sports database.
The important thing to know is that Joe can control everything he sends to the server. He can see the cookie contents, post data and get variables. Lets say that Joe wants to check a friends team score. The site allows Joe to sort his scores using GET variables. Joe just places in an escape character and appends some SQL to view his friends score.
3. Input data validation
Think of a web application like a game of D&D, if you are out on the desert plains with a 12th level Barbarian named Ogar, whats keeping the player from making Ogar go left when the DM expects the player to go right? There is no reason Ogar the barbarian can't sit down and whittle a set of dice, mark up a parchment with character stats and then play Cube farms & Bosses.
You have a nice HTML page which provides for the intended actions of the user but everything in the browser or on the computer is out of your control. Java script, plug ins, input, cookies and URLs are not controllable and therefore cannot be fully trusted.
The key is limiting the users choices, and abstracting their decisions. If your scripts inputs expect a phone number, then the input should only be numbers or else its invalid. If there is only search methods A,B or C then if the input isn't A,B or C then it has to be invalid. Simply filtering out known bad data such as embedded javascript isn't 100% effective, if the data type is contaminated it cannot be trusted.
The quality of the data you take in is important, the other part of this is abstraction of the users decisions. If a persons available choices are A,B and C, and internally you identify A, B and C as actions and everything else as false input then that is more effective than allowing user input directly control your data.
4. Trusted processing
Assuming that you have done your due diligence and secured your server, it is more trustworthy of a computing platform than your clients workstation. A clients workstation could be infected with mal-ware, it could have a malfunctioning or obsolete browser or the user could intentionally manipulate the http variables to trick the application. Input validation cannot be done using JavaScript alone, trusting JavaScript or any other plug in to obfuscate your applications process just isn't a good idea. Client side scripting is good for enhancing the presentation and for providing a means to communicate information effectively to the user but it should not be relied upon to process information.
5. Database queries
Filtering valid data is just one step, the other step is on your data sources such as MySQL, Postgres, Oracle ... most modern Databases allow you to do a prepared statement which auto-magically binds input into a SQL string. Because its binding data directly to a variable the chances that a user's escape string can hijack the SQL query is greatly diminished. By limiting the users input to only data and not to the program execution process you greatly reduce the possibility of your script becoming compromised.
For example:
"http://example.com/mypage.php?display=select * from mydatabase.mytable where user=Joe order by date;"
Including SQL in a user accessible variable is a really really bad idea. Even if it is on a link that Joe wont see and Java script is used to obscure the URL. Joe controls the machine so any obfuscation used will never be effective. What is stopping Joe from substituting "select 'joe' as user password as score, currdate() as date from mysql.users where username=root;"?
6. Raising the bar
There are alot of "Magic Bullet" solutions to web application security. Application firewalls monitor information going both to and the web application. SQL application firewalls filter out suspicious SQL commands going to your RDBMS server. For most developers, these solutions are
either too expensive or too complex to implement for individual web applications. Here are some PHP security plug ins and tools to help raise the bar on the cheap.
When you use this or any other security plug-in, it is vital that you evaluate your applications baseline performance to know what is normal behavior. For instance PHPBB2, a popular PHP bulletin board application display a large list of forums. And mysteriously the settings would not save. I was using Suhosin and this was caused because the number of variables being posted was above Suhosin's default limit and the script was aborting before it could save the changes.
On the server side there is Green SQL, which is a MySQL sanitizer/proxy. Then there is mod_security which hardens Apache and turns it into an application firewall. mod_chroot is similar in the basic functionality of mod-security except it just chroots Apache transparently to the user. Then there are web application security scanners such as the ones included in Nesssus.
Wapiti checks for cross-site scripting (XSS), injection and other common issues. OWASP's WebScarab is a good utility for testing user access to http variables on the client side and intercepting the raw http conversation between the client and the server.
7. Informative resources
Breach Security "Mod Security home page". (Accessed April 2009)
http://www.modsecurity.org
Dawes, Rogan "OWASP WebScarab Project" (Accessed April 2009)
http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project
Esser, Stefan "Hardened PHP Project" (Accessed April 2009)
http://www.hardened-php.net/suhosin/
Freitag, Pete "20 ways to Secure your Apache Configuration" (Accessed April 2009)
http://www.petefreitag.com/item/505.cfm (Posted Dec 5, 2005)
Green SQLProject "Green SQL home page". (Accessed April 2009)
http://www.greensql.net
Hobbit "mod_chroot" (Accessed April 2009)
http://core.segfault.pl/~hobbit/mod_chroot/
OWASP Foundation. "Main Page" (Accessed April 2009)
http://www.owasp.org/index.php/Main_Page
Tenable network security inc. "Nessus Product Page" (Accessed April 2009)
http://www.nessus.org/nessus/
The Apache Foundation. "Apache HTTP Server Project". (Accessed April 2009)
http://httpd.apache.org/
The PHP Group. "PHP: Hypertext Preprocessor". (Accessed April 2009)
http://www.php.net/
Surribas, Nicolas "Wapiti Web application vulnerability scanner / security auditor" (Accessed April 2009)
http://wapiti.sourceforge.net/
See also:
Ax0n's OAMP (Apache, Mysql, PHP on OpenBSD) Article:
http://www.h-i-r.net/2008/12/sysadmin-sunday-amp-on-openbsd-44.html
Asmodian X's Name based hosting mini-howto:
http://www.h-i-r.net/2008/10/sysadmin-sunday-apache-name-based.html
Asmodian X's Workbench - Suhosin :
http://www.h-i-r.net/2008/12/asmodians-workbench-suhosin-hardened.html
Labels: amp, apache, application security, password, php, Websecurity
2008-12-21
Sysadmin Sunday: AMP on OpenBSD 4.4
FYI - There's now a page that covers OAMP for all recent versions of OpenBSD.
PKG_PATH=ftp://ftp.openbsd.org/pub/OpenBSD/4.4/packages/i386/My user-level account is also in the wheel group, and the following line was uncommented from /etc/sudoers:
export PKG_PATH
%wheel ALL=(ALL) SETENV: ALLThat means anyone in wheel can run anything with sudo as any other user (root by default)
-bash-3.2$ sudo pkg_add php5-mysql mysql-server--- php5-core-5.2.6 -------------------
To enable the php5 module please create a symbolic
link from /var/www/conf/modules.sample/php5.conf
to /var/www/conf/modules/php5.conf.
ln -s /var/www/conf/modules.sample/php5.conf \
/var/www/conf/modules
The recommended php configuration has been installed
to /var/www/conf/php.ini.
Don't forget that the default OpenBSD httpd is chrooted
into /var/www by default, so you may need to create support
directories such as /var/www/tmp for PHP to work correctly.
--- php5-mysql-5.2.6 -------------------
You can enable this module by creating a symbolic
link from /var/www/conf/php5.sample/mysql.ini to
/var/www/conf/php5/mysql.ini.
ln -fs /var/www/conf/php5.sample/mysql.ini \
/var/www/conf/php5/mysql.ini
sudo cp /var/www/conf/modules.sample/php5.conf \/var/www/conf/modules/
sudo cp /var/www/conf/php5.sample/mysql.ini \/var/www/conf/php5/
sudo /usr/local/bin/mysql_install_dbsudo /usr/local/share/mysql/mysql.server startsudo /usr/local/bin/mysqladmin \-u root password 'your-password'
sudo vi /etc/rc.conf(find httpd_flags once editing the file)# use -u to disable chroot, see httpd(8)
httpd_flags=""-or-httpd_flags="-u"
You can launch apache easily from the command line now by executing httpd, so you don't need to reboot. Use -u if you specified it in /etc/rc.conf.
sudo httpd
sudo vi /etc/rc.local(add the following line to the end)/usr/local/share/mysql/mysql.server start
If it shows the menu, then MySQL is running and the password you configured is working.mysql_setpermission -u root
Password for user root to connect to MySQL: your-password
######################################################################
## Welcome to the permission setter 1.4 for MySQL.
## made by Luuk de Boer
######################################################################
What would you like to do:
1. Set password for an existing user.
2. Create a database + user privilege for that database
and host combination (user can only do SELECT)
3. Create/append user privilege for an existing database
and host combination (user can only do SELECT)
4. Create/append broader user privileges for an existing
database and host combination
(user can do SELECT,INSERT,UPDATE,DELETE)
5. Create/append quite extended user privileges for an
existing database and host combination (user can do
SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,
LOCK TABLES,CREATE TEMPORARY TABLES)
6. Create/append full privileges for an existing database
and host combination (user has FULL privilege)
7. Remove all privileges for for an existing database and
host combination.
(user will have all permission fields set to N)
0. exit this program
Make your choice [1,2,3,4,5,6,7,0]:
<?phpphpinfo();?>
Hit it with your web browser to make sure it loads. It should show you information about your PHP installation, including the MySQL module.

- Making a hard link to /var/run/mysql/mysql.sock within /var/www somewhere, and editing the php.ini file accordingly
- Disabling apache chroot by setting httpd_flags="-u"
- Checking the php, mysql, and apache error logs for more information about what went wrong
2008-10-19
Sysadmin Sunday: Apache Name Based Hosting mini-howto
Apache Name Based Hosting configuration
by Asmodian X
Contents
1. Description
2. Getting started
3. Base Filesystem Layout
4. Base Configuration
5. Name based hosting configuration (WWW only)
6. Name based hosting configuration (SSL single site)
7. Implementing the configuration
1. Description
Apache name based hosting configuration using Debian Linux or Ubuntu Linux Server edition. This is intended for intermediate Linux/UN*X administrators. You will require the Apache mod_vhost module, along with apache2, openssl and whatever other apache services you want.
2. Getting started
If you have not already installed apache ...
At the Ubuntu/Debian Linux prompt:
$sudo apt-get install apache2
$sudo a2enmod vhost_alias
$sudo a2enmod ssl
3. Base Filesystem Layout
htdocs layout:
/data/sites
• ssl
⁃ symlink to site folder in www
• www
⁃ site_url
⁃ htdocs
⁃ cgi-bin
This could easily be turned into Suse's standard of /srv/www/sites/www ...etc . the site_url needs to be exactly what the end user will type in as their dns url. so there needs to be a folder
called host.example.com as well as www.host.example.com. This is easily accomplished with symlinks in Linux.
Config layout: (based off of ubuntu/debian standard)
/etc/apache
• sites_available
• sites_enabled
• modules_available
• modules_enabled
• ssl
⁃ sitename
⁃ certificate file
The ssl directory could easily be in /etc/ssl but this is up to you.
4. Base Configuration
This is the default Debian/ubuntu apache.conf file. No changes were made here.
ServerRoot "/etc/apache2"
LockFile /var/lock/apache2/accept.lock
PidFile ${APACHE_PID_FILE}
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule>
<IfModule mpm_worker_module>
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
AccessFileName .htaccess
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
DefaultType text/plain
HostnameLookups Off
ErrorLog /var/log/apache2/error.log
LogLevel warn
Include /etc/apache2/mods-enabled/*.load
Include /etc/apache2/mods-enabled/*.conf
Include /etc/apache2/httpd.conf
Include /etc/apache2/ports.conf
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
ServerTokens Full
ServerSignature On
Include /etc/apache2/conf.d/
Include /etc/apache2/sites-enabled/
Listen 80
Listen 443
5. Name based hosting configuration (WWW only)
UseCanonicalName Off
LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
DirectoryIndex index.html index.shtml index.php index.htm
<Directory /data/sites/www>
Options FollowSymLinks
AllowOverride All
</Directory>
<VirtualHost *:80>
Servername host.example.com
CustomLog /var/log/apache2/access_log.host.vhost vcommon
VirtualDocumentRoot /data/sites/www/%0/htdocs/
VirtualScriptAlias /data/sites/www/%0/cgi-bin/
</VirtualHost>
WWW name based hosting requires the use of the mod_vhost apache2 module. Any interface that apache is listening to will check to see what hostname was being called and match it to a directory name in /data/sites/www/.
6. Name based hosting configuration (SSL single site)
UseCanonicalName Off
LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
DirectoryIndex index.html index.shtml index.php index.htm
<Directory /data/sites/ssl>
Options FollowSymLinks
AllowOverride All
</Directory>
<VirtualHost 1.2.3.4:443>
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/generic/generic.crt
Servername host.example.com
CustomLog /var/log/apache2/access_log.host.vhost vcommon
VirtualDocumentRoot /data/sites/ssl/host.example.com/htdocs/
VirtualScriptAlias /data/sites/ssl/host.example.com/cgi-bin/
</VirtualHost>
Alternatively you can add another virtual host for port 80 in-case you want to exclude this site from the name based section above.
SSL wants a static port, IP or both. Its easier to have a static IP but either will do. Also, you will need a dedicated ssl certificate for each site (lest you get an SSL error message on the client side) or you need to get a Wildcard SSL certificate for your domain. This is assuming you are assigning sites under the example.com domain such as site1.example.com, site2.example.com ...etc.
If you are dealing with different DNS names for each site then individual certificates are needed.
7. Implementing the configuration
When installing the configuration take these steps:
1. Remove the /etc/apache2/sites_enabled/default configuration symlink
2. Create the generic name based hosting files (listed above) into files in the /etc/apache2/sites_available folder.
3. Create symlinks from the sites_available configuration files into the sites_enabled folder.
4. restart apache.
2008-04-11
ApacheFriends XAMPP makes Apache setup easy
I've been using XAMPP on Windows (which I'm forced to use at work) for a few years. I write a lot of custom PHP stuff to help me with my day job, and I also like to test functions or classes I write before I push it out to production. ApacheFriends XAMPP is an easy way to get a basic Apache installation up and running with some of the most popular add-ons including PHP and MySQL. It installs in OS X and many Linux distributions as well.
While nothing can replace a streamlined, custom-compiled AMP Stack set up just the way you need it, XAMPP affords busy sysadmins (and web developers that don't want to be sysadmins!) the ability to get a functional web dev environment up and running with ease.
Go ahead, give XAMPP a shot!
2008-01-19
Sysadmin Sunday: OpenBSD 4.2, Apache, MySQL, PHP (OAMP?)
It used to be that some stuff had to be compiled by hand to make everything work just right, but the package/port guys finally nailed it. With the help of obsd_pkgscripts, OAMP is a breeze. The benefits of running your AMP-driven website atop OpenBSD are many, not the least of which are the facts that it's a minimalistic, secure, and high-performance platform out of the box.
OpenBSD already ships with Apache. It's a patched and tweaked version of Apache, but it's Apache all the same. You're already halfway to OAMP land with OpenBSD and Apache installed out of the box.
First, install the MySQL Server. I obviously chose to use my pkg_get.sh tool for this, but it's not needed.
$ pkg_get.sh mysql-server
Attempting to fetch/install package...
mysql-client-5.0.45: complete
p5-DBD-mysql-3.0008:p5-Net-Daemon-0.39: complete
p5-DBD-mysql-3.0008:p5-PlRPC-0.2018p0: complete
p5-DBD-mysql-3.0008:p5-DBI-1.53: complete
p5-DBD-mysql-3.0008: complete
mysql-server-5.0.45: complete
--- mysql-server-5.0.45 -------------------
You can find detailed instructions on how to install a database
in /usr/local/share/doc/mysql/README.OpenBSD.
Next, that README contains some useful information for more advanced installations and performance, but summarized, follow these instructions. I use sudo, and rarely use the root account. I recommend doing the same.
Create the DB:
-bash-3.2$ sudo /usr/local/bin/mysql_install_dbStart MySQL:
-bash-3.2$ sudo /usr/local/share/mysql/mysql.server startTo make MySQL Start up at boot, add the above mysql startup line to /etc/rc.local without the "sudo" at the beginning (optional but highly recommended). There is a "theoretically correct" start-up snippit on the documentation, but I've found this works just as well.
Set a password for mysql's root user (choose a better one than this):
-bash-3.2$ sudo /usr/local/bin/mysqladmin -u root password 'new-password'That's pretty much it as far as getting MySQL up and running is concerned. Now we just need to get PHP installed with the MySQL client library...
-bash-3.2$ sudo pkgscripts/pkg_get.sh php5-mysqlThen you have to follow the post-install instructions:
Attempting to fetch/install package...
php5-core-5.2.3: complete
php5-mysql-5.2.3: complete
--- php5-core-5.2.3 -------------------
To finish the install, enable the php5 module with:
/usr/local/sbin/phpxs -s
To enable parsing of PHP scripts, add the following to
/var/www/conf/httpd.conf:
AddType application/x-httpd-php .php
Copy the config file below into /var/www/conf/php.ini
/usr/local/share/examples/php5/php.ini-recommended
Don't forget that the default OpenBSD httpd is chrooted
into /var/www by default, so you may need to create support
directories such as /var/www/tmp for PHP to work correctly.
--- php5-mysql-5.2.3 -------------------
Enable this module in php.ini using the following command:
/usr/local/sbin/phpxs -a mysql
-bash-3.2$ sudo /usr/local/sbin/phpxs -sEdit /var/www/conf/httpd.conf and add the below line with the other AddTypes:
-bash-3.2$ sudo /usr/local/sbin/phpxs -a mysql
AddType application/x-httpd-php .php
I also recommend since we're going to be running PHP, adding index.php to the DirectoryIndex line:
DirectoryIndex index.html index.php
Save the httpd.conf file.
Now, copy the php.ini file over from the examples:
-bash-3.2-$ sudo cp \Now, make sure apache is set to start.
/usr/local/share/examples/php5/php.ini-recommended \
/var/www/conf/php.ini
If you plan on keeping all your web-related content content in /var/www, find the httpd_flags line in /etc/rc.conf and change it to httpd_flags=""
If you intend on giving users traditional ~username (public_html) directories, start apache without being chrooted. Chroot is more secure, but it's a royal pain if you want user home-directories on a vanilla OAMP box, and beyond the "quick and dirty OAMP" scope of this article. Find the httpd_flags line in /etc/rc.conf and change it to httpd_flags="-u" to disable chroot if you must.
The above change to httpd_flags will make apache auto-start upon reboot. You can manually start it with apachectl, though:
-bash-3.2$ sudo apachectl startMake a phpinfo example php file and move it into the web root.
/usr/sbin/apachectl start: httpd started
-bash-3.2$ echo "<?phpinfo();?>" > phpinfo.php
-bash-3.2$ sudo mv phpinfo.php /var/www/htdocs/Then test it out by pointing a browser to your new phpinfo.php file (example: http://10.23.45.67/phpinfo.php ) and you should see output from PHP. If you see a blank screen or just the phpinfo line, something went wrong. Re-check your steps.
There you have it! As a test, I installed Joomla on this system (screen shot below). Joomla is a popular open-source CMS. I unpacked it into /var/www/htdocs/joomla and pointed my browser to it, following all of its instructions. This includes making a database, changing permissions on some of the Joomla files, and modifying some values in php.ini. The installation went off without any problems just like it would on any LAMP box. I'd imagine you'll see similar results with other *AMP packages such as phpMyAdmin, Xoops, and others.
2007-12-05
Rickrolling with mod_rewrite
Comic Credit:XKCD
Rickrolling is one of the latest goofy internet pranks, memes, or whatever you want to call it. By strictest definition, to rickroll someone is to send them a link that seems to be for something interesting, but actually takes them to a video of Rick Astley's "Never gonna give you up". These can be via e-mail, instant message, or even discussion forums.
Example of rickroll bait:
Did you see the video of the new spy plane the military is working on?!
Fast forward to today. I find out that some morons have planned to have a little fun with one of the websites that I help with. It's not my site, but run by a client and friend of mine. Not too big of a deal, just some bored teenagers, probably. Not sure what they were up to, but it probably involved lots of forum trolling, trash talking, or spamming. Who knows? I figured I would rickroll these twerps. If they click on the URL they posted in their little forum, they won't get the site they wanted. They will get Rick Astley instead. Meanwhile, the site works fine for everyone else.
In order to do this, I used Mod_Rewrite for apache, and added this to my .htaccess file. In this example, people who click on a link to my site from anywhere on http://www.evil.net will get rickrolled:
RewriteEngine on
RewriteCond %{HTTP_REFERER} ^http://www\.evil\.net [NC]
RewriteRule .* http://www.youtube.com/watch?v=eBGIQ7ZuuiU [R]
The first line just initializes the rewrite engine.
The second line checks the HTTP_REFERER server variable to see if it starts with "http://www.evil.net" (It's a regular expression, "^" means "starts with" and the periods have to be escaped with a backslash or else they're treated as wildcard characters) The [NC] simply means "no case" so that the referer URL is case-insensitive.
The third line tells apache what to do. In this case, it replaces the entire url (.*) with a link to the video on YouTube. The code at the end specifies what kind of rewrite. In this case, [R] means that the web server passes an HTTP 302 status, telling the browser that the URL has been temporarily moved. And you just got rickrolled.
Related Links:
Mod_Rewrite Tips site
Regular-Expressions.info (for forming good RegEx rules)
XKCD.com