Tag: apache

  • Securing a LAMP Stack

    Introduction

    LAMP = Linux, Apache, MySQL, PHP

    This application stack is how a ton of web apps run. That includes WordPress, the CMS (content management system) I used to build this blog. When one googles “how to build a LAMP stack” as I did when setting up this website, there are plenty of decent guides.

    However, few touch on security.

    Perhaps a default, fresh install of these applications leaves a web app secure against basic botnet attacks. But the lack of specific information on building these securely gave me an icky feeling I just couldn’t shake. In this blog post, I will document the process of building a LAMP stack with security in mind.

    Secure Foundation

    Before jumping right into setting up your LAMP stack and web server, I recommend starting your server from a secure foundation. I am building everything on a Debian 12 EC2 instance. The process may differ slightly on different Linux distributions.

    First, update and upgrade the system. This ensures you’re using the latest packages.


    sudo apt update && sudo apt upgrade -y

    Next, ensure automatic updates are configured. On Debian, we can accomplish this using unattended-upgrades, which comes default with Debian 12. Just in case, the code below tries to install it anyway.


    sudo apt install unattended-upgrades -y
    sudo dpkg-reconfigure unattended-upgrades

    Press enter to select “Yes” on the popup. There are some more configurations to be done to make the most of unattended-upgrades. The following code adjusts its config file:


    # Adjust configuration file to remove unused dependencies
    sudo sed -i 's/\/\/Unattended-Upgrade::Remove-Unused-Dependencies "false";/Unattended-Upgrade::Remove-Unused-Dependencies "true";/' /etc/apt/apt.conf.d/50unattended-upgrades
    
    # Adjust configuration file to enable automatic reboots when needed
    sudo sed -i 's/\/\/Unattended-Upgrade::Automatic-Reboot "false";/Unattended-Upgrade::Automatic-Reboot "true";/' /etc/apt/apt.conf.d/50unattended-upgrades

    Now that unattended-upgrades is setup, take a moment to consider securing remote access. Where will you be accessing the web server from? In my case, where a web server is running on AWS, I utilize a Security Group to limit SSH access from my home’s public IP. This can be adjusted pretty easily if working from another location. Of course, you’ll want your server’s HTTP/S port open to the internet, but there are additional ways to lock that down which I’ll go over shortly.

    Installing the Apps

    Now we shall install Apache.


    sudo apt install apache2 -y


    Next, install MariaDB. This is the database portion of the LAMP stack.


    sudo apt install mariadb-server mariadb-client -y
    # start and enable mariadb service
    sudo systemctl start mariadb
    sudo systemctl enable mariadb


    Mysql/Mariadb include a secure install script. Run the command:


    sudo mysql_secure_installation




    And follow the prompts. The prompts suggest the most secure options so I suggest going with those.

    Next, install PHP and the necessary modules.


    sudo apt install php libapache2-mod-php php-mysql -y




    Now you should have a functional web server. You can install WordPress as I have, or perhaps another CMS. Or nothing. But it is certainly not secure. Many guides stop here, but I would like to mention some fundamental tips for securing the server.

    Securing Your Baby

    You’ve birthed a beautiful LAMP stack, and now you must secure it. At least a little, no?

    Set Up HTTPS

    This is important. Even if you’re merely hosting a blog, web traffic should be encrypted. Browsers will warn users if your website doesn’t support HTTPS, making your site look suspicious. Also, if you’re using WordPress, installing it before setting up HTTPS means your site credentials will be sent in clear-text over the internet.

    Note that you need to have a domain pointed to your web server in order for this to work. If you’re unsure what this means, you basically need to add a DNS A record with your domain’s registrar. For more info, google it.

    Install certbot and run it.


    sudo apt install certbot python3-certbot-apache -y
    sudo certbot --apache

    Certbot will get your website set up with a certificate from Let’s Encrypt. Follow the prompts, including specifying which domain you have set up. Let’s Encrypt’s servers need to be able to reach the site, so you may need to open up access to the internet on port 80 if you haven’t already. It’s pretty simple; once the script is finished, you should be ready to go with HTTPS.

    Ensure Proper Permissions

    The contents of Apache’s root web directory, /var/www/html/, should be owned by user:group www-data:www-data. This is the user that the Apache process runs as. If these files are owned by root, for example, compromise of the server will mean the attacker has root access.

    To set the proper permissions, run the following commands:


    sudo chown -R www-data:www-data /var/www/html
    sudo chmod -R 755 /var/www/html

    Disable Unneeded Modules

    During my research into this subject, I was surprised to learn there are numerous Apache modules enabled by default that pose some risk. For example, the autoindex module shows the user an index of files in the absence of an index.html file; this can reveal unwanted or private information to browsers.

    After renaming index.html, we can see autoindex serves a directory of files

    Additional modules to consider for disabling are:

    • status – provides a web-based interface showing server activity and performance metrics
    • userdir – allows users to serve content from their home directories (e.g., http://example.com/~username)
    • cgi – enables the execution of CGI scripts
    • includes – allows server-side includes (SSI) in HTML files
    • dav/dav-fs – enable WebDAV functionality for file management over HTTP
    • proxy/proxy_* – enable Apache to function as a forward or reverse proxy
    • info – provides detailed server information (e.g., installed modules, configuration directives) via a web interface
    • rewrite – enables URL rewriting (e.g., for pretty URLs in WordPress or Laravel)
    • chatGPT gave me this list of modules, which I reviewed for relevance

    To view which modules are currently running on your server:
    sudo apache2ctl -M

    To disable a module:
    sudo a2dismod <module_name>

    Add Security Headers

    Security headers help protect against a variety of attacks like XSS (cross-site scripting), clickjacking attacks, and more. The details of each header are beyond the scope here, but feel free to look further into them.

    To enable security header functionality in Apache:
    sudo a2enmod headers

    Now, edit the default configuration file at /etc/apache2/sites-available/000-default-le-ssl.conf (your filename may differ):
    sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf

    Add the following headers under ‘<VirtualHost *:443>’:

    Header always set Content-Security-Policy "default-src 'self';"
    Header always set X-Frame-Options "DENY"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    Header always set Referrer-Policy "no-referrer"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    Header always set Cross-Origin-Embedder-Policy "require-corp"
    Header always set Cross-Origin-Opener-Policy "same-origin"
    Header always set Cross-Origin-Resource-Policy "same-origin"

    After saving the file, restart the apache service:
    sudo systemctl restart apache2

    A fun way to test the effectiveness of your security headers is securityheaders.com; you enter your URL and the site scans your site and gives a grade. After adding these headers, it gave me an A+.

    NOTE: while the Content-Security-Policy header is certainly the most secure config, it is overly-restrictive if using something like WordPress. It prevents the page from loading any content not hosted by the server itself.

    Web App Firewall / Change Server Name

    Let’s now deploy an open-source web application firewall (WAF), modsecurity. Aside from being a WAF, it will let us change the server name so its less obvious this is an apache server, which is cool.


    sudo apt install libapache2-mod-security2
    sudo a2enmod security2
    sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
    sudo nano /etc/modsecurity/modsecurity.conf

    With the conf file open, add the following line:
    SecServerSignature "nginx"

    Then save and close the file and restart the apache service. Look, when I curl my website, now it looks like an nginx server!

    Not to mention there is now a WAF running.

    However, the WAF is using a default config. It probably needs to be tuned. Alas, that is a problem for another day. At the risk of writing a book, I will now summarize.

    Conclusions

    A lot goes into securing a web app, it seems. Just going ahead and installing the basic components really doesn’t cut it. It’s fun to learn and try these things out, but I think in the long run I’d rather run my blog on a PAAS solution somewhere. The onus of security moves toward the service provider, at that point. Another option would be to utilize something like a CIS hardened image. These are images provided on the major cloud service platforms that are pre-configured for security according to the rigorous standards of the CIS benchmarks.