wiki:secureweb

LAMP Installation and Web hardening

LAMP is one of the most common web systems we find today. Letters L A M P stands for Linux , Apache, MySQL & PHP.

From your yesterday’s work, we already have our first objective ‘L’, i.e. Linux or in our case its Ubuntu. Therefore, let’s see how to install other three and then in to some security hardening.

Setting the Hostname and FQDN

Remember this VM is a clone of your pc.userX.ws.learn.ac.lk. Therefore you have to change some settings in order to make this vm unique.

Setting up hostname

  • Login to the vm. change to root user
    $sudo su
    
  • Give your password
  • Edit /etc/hostname
    #nano /etc/hostname
    
    • Change pc to www
    • Save and Exit
  • also edit /etc/hosts file to change 127.0.0.1 pc."your domain".ws.learn.ac.lk pc to 127.0.0.1 www."your domain".ws.learn.ac.lk www

IP Set up

Edit /etc/network/interfaces files to include your IP addresses in your pc

  • Login to the vm. change to root user
    $sudo su
    
  • Give your password
  • Edit /etc/network/interfaces
    #vi /etc/network/interfaces
    
  • Find the following line
    iface eth0 inet dhcp
    

Note: "eth0" is the name of your virtual interface. It could also be something like "enp0s3". If so you will use that instead of eth0

  • Change it to
    #iface eth0 inet dhcp
    
  • Add the following lines (Get your ldap IP Address from iptable)
    iface eth0 inet static
        address "Your www IP address"
        netmask 255.255.255.0
        network 192.248.6.0
        broadcast 192.248.6.255
        gateway 192.248.6.254
        dns-nameservers 192.248.1.161
        dns-search yourdmain 
    

When you completed the IP settings of of VM, restart the vm and then login to confirm correct IP settings.

Before you get started, make sure you set up your server so that it correctly resolves its hostname to fully qualified domain name (FQDN). This will be necessary in order for your certificates to be validated by clients.

check FQDN by

hostname -f   

Prerequisites

Before we begin, we need to have a non-root user account with sudo privileges set up on your Ubuntu 16.04 LTS server clean installation.
Check whether you can ping your vm from the pc using its domain name www.'yourdomain'.ws.learn.ac.lk

Installation of Apache

Apache is a web server application that is widely used in the internet for more than 20 years and it is a well-documented piece of Free and Open Source Software managed by Apache Foundation. (https://httpd.apache.org/)

Before installing we need to update our repositories. Therefore we will first add debian apache repo to our list and do a update on the list. Since we will be using sudo commands, It will ask you for your user's password as these processors will be granted root privileges.

sudo add-apt-repository ppa:ondrej/apache2

When Asked press ‘Enter’ to Continue. Once the ppa is imported do an update.

sudo apt-get update

Once the repo lists are updated run,

sudo apt-get install apache2

When asked press Y and hit Enter to continue, and the installation will proceed.

Check installed apache version details by issuing,

$ apache2 -v

NOTE: if you had installed apache2 while installing Ubuntu OS then we should update it to the latest by,

sudo apt-get --only-upgrade install apache2 -y

Now goto your browser and type http://www.'your domain'.ws.learn.ac.lk and check whether you are able to access the apache test page.

MySQL Installation

Once the web server is installed and running we need to install a database management system to host our dynamic data. For that we use MySQL database as another popular FOSS.

So to install MYSQL run,

sudo apt-get install mysql-server

Again you will be asked to press Y to continue. During the installation process you will be asked to type in and confirm a root password for your MySQL system. Please keep in mind that MySQL root is also similar to root access of your server and therefore choose a strong and unique password, never leave it blank.

As the installation completes let’s tighten some security in MySQL by running,

sudo mysql_secure_installation

Enter your MySQL root password when asked. As the first step it will ask

VALIDATE PASSWORD PLUGIN

where this will make your passwords associated with databases much stronger by enforcing password restrictions. Once you click y it will give three options LOW, MEDIUM, STRONG. Then select a level of password validation. Make sure to keep in mind that if you enter 1, for the medium level, you will receive errors when attempting to set any password which does not contain numbers, upper and lowercase letters, and special characters.
Then there will be several questions asked, please enter Y for every answer and enter.
Once the script ends running we can test our MySQL instance by login in to it.

mysql –u root –p

Enter your MySQL root password when requested.

Install PHP 7

As the last option of LAMP lets install PHP version 7.

type in,

sudo apt-get -y install php7.0 libapache2-mod-php7.0

the switch –y will automatically put yes on the installation process when it is prompted.
Once the installation is finished restart apache.

sudo service apache2 restart

To check php, lets create a test php file.

sudo nano /var/www/html/info.php

Note: /var/www/html/ is the default document root for apache in Ubuntu unless you have changed it in apache configuration.

Enter the following in info.php

<?php
phpinfo();
?>

Now let us call that file in a browser (e.g. http://www.'yourdomain'.ws.learn.ac.lk /info.php)

If your PHP 7 is working you will see all your php server settings in a one single place.

Enabling Virtual Hosts

Create two directories on /var/www/ to host two separate web sites.

sudo mkdir /var/www/web1
sudo mkdir /var/www/web2

Create index pages on each directories containing following.

sudo nano /var/www/web1/index.php

You may change the content as appropriate.

<html>
<head>
<title>Web 1</title>
</head>
<body>
<h1> <?php
Echo "Hello, I’m Web1";
?>
</h1>
</body>
</html>

Default host configuration is located in /etc/apache2/sites-available/000-default.conf which serves any requests coming to its domain name or IP address. To make other two domains work, lets create virtual host files for each domain names;

sudo nano /etc/apache2/sites-available/web1.conf

with the following content,

<VirtualHost *:80>
ServerAdmin admin@yourdomain.ws.learn.ac.lk
ServerName yourdomain.ws.learn.ac.lk
ServerAlias web1.yourdomain.ws.learn.ac.lk
DocumentRoot /var/www/web1
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Then create the virtual host for web2 as web2.conf on the same directory as web1.conf with the folowing.

<VirtualHost *:80>
ServerAdmin admin@yourdomain.ws.learn.ac.lk
ServerName yourdomain.ws.learn.ac.lk
ServerAlias web2.yourdomain.ws.learn.ac.lk
DocumentRoot /var/www/web2
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Once both files are written these needs to be enabled by,

sudo a2ensite web1.conf
sudo a2ensite web2.conf

Now restart the apache.

Do a nslookup for www.yourdomain.ws.learn.ac.lkand find the IP Addressof yourweb server and edit your pc host file and include following.(assume your IP is 192.248.X.X)

192.248.X.X  web1.yourdomain.ws.learn.ac.lk
192.248.X.X  web2.yourdomain.ws.learn.ac.lk

Note: For Linux:host file is /etc/hosts , edit with nano as sudo.
For Windows:host file is %SystemRoot%\System32\drivers\etc\hosts, open with Notepad in Run As Admin mode.

and restart your pc’s....

check your browsers for following and see how three websites are hosted in one server.

http://www.yourdomain.ws.learn.ac.lk
http://web1.yourdomain.ws.learn.ac.lk
http://web2.yourdomain.ws.learn.ac.lk

CGI Scripts

CGI stands for Common Gateway Interface are useful for creating dynamic content on web page by transferring data from server to client. These scripts can be written in many languages such as bash, c, java, perl, python etc.
First we need to create a script firstbash.cgi in following location /usr/local/cgi-bin/ , you may need to create it as sudo.

#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "My first CGI script"

Give the script file execute permissions

sudo chmod 705 /usr/local/cgi-bin/firstbash.cgi

Now to add this CGI on our web2 virtual host, edit /etc/apache2/sites-available/web2.conf as follows.

<VirtualHost *:80>
ServerAdmin admin@yourdomain.ws.learn.ac.lk
ServerName yourdomain.ws.learn.ac.lk
ServerAlias web2.yourdomain.ws.learn.ac.lk
DocumentRoot /var/www/web2
<Directory /var/www/web2>
Require all granted
</Directory>
ScriptAlias /cgi-bin/ "/usr/local/cgi-bin/"
<Directory "/usr/local/cgi-bin/">
Options +ExecCGI
AddHandler cgi-script .cgi
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

After editing web2.conf lets enable CGI apache module and restart the server.

sudo a2enmod cgi
sudo systemctl reload apache2

Visit following link and check-out your script.

http://web2.yourdomain.ws.learn.ac.lk/cgi-bin/firstbash.cgi

Apache Hardening

  • Hide Apache version details:

By default, Apache displays the version of Apache web server installed with the name of the operating system. To hide this information, you need to edit /etc/apache2/conf-enabled/security.conf

sudo nano /etc/apache2/conf-enabled/security.conf

Add/edit the following line:

ServerSignature Off
ServerTokens Prod
TraceEnable Off
  • Stop Directory Browsing

Rename index.html in /var/www/html as index2.html and try to access web server from outside. You will see the directory Listing as now we don’t have an Index. But better stop displaying directory listing. Therefore, edit /etc/apache2/apache.conf and remove Indexes key word from any Directory listing such as,

<Directory /var/www/>
#
Options Indexes FollowSymLinks
Options -FollowSymLinks
AllowOverride None
Require all granted
</Directory>

and restart apache. Now go back to your default web portal and check the results.

file/folder permissions

When you create or modify documents under /var/www/ as sudo those files and directories will belong to root user and root group. Apache is usually run by a user www-data and www-data group in Ubuntu. Therefore, if any document belongs to root will also be published as root has higher precedence than www-data. But if some malicious content are hosted, they can also be run under root opening lot of vulnerabilities to the public.

To secure publically accessible areas we can change user permissions by,

sudo chown -R www-data:www-data /var/www

Also if we had directories that are open for users to upload content we can restrict access by modifying access modes.

sudo chmod 664 /var/www/uploads

That will change file permissions to rw-rw-r—

Password protected Directory

When securing a directory it is a common practice we use a password to enter that path. Also in apache2 we can specify a password by creating an apache user and using .htaccess as needed.

First install Apache Utiities;

sudo apt-get install apache2-utils

On your virtual host configuration file add or modify following inside the <Directory> ... </Directory>.

AllowOverride AuthConfig

Next create an authenticate user.

sudo htpasswd -c /etc/apache2/.htpasswd yourname

This will ask you to enter a new password and conform it for the new user. If you want to add another user, try with the same command above with new username. You can view the contents of the .htpassword file by

sudo cat /etc/apache2/.htpasswd

next we need to grant permission to www-data user.

sudo chown www-data:www-data /etc/apache2/.htpasswd
sudo chmod 0660 /etc/apache2/.htpasswd

After that create a directory called “mystuff” inside the directory web1, create an html page of your choice inside the directory as sudo and change ownership to www-data.

sudo mkdir /var/www/web1/mystuff
sudo nano /var/www/web1/mystuff/index.html
sudo chown –R www-data:www-data /var/www/web1/mystuff/*

Now create .htaccess file inside mystuff directory

sudo nano /var/www/web1/mystuff/.htaccess

Add following content

AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

Now restart apache and browse to the newly created directory from your browser and check what is changed.

Enabling HTTPS with self-signed certificates

Create self-signedCertificates on to a directory /etc/ssl using openssl

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache_prv.key -out /etc/ssl/certs/apache_crt.crt

You will be asked series of questions, answer them carefully

Country Name (2 letter code) [AU]:LK
State or Province Name (full name) [Some-State]:Kandy
Locality Name (eg, city) []:Peradeniya
Organization Name (eg, company) [Internet Widgits Pty Ltd]:YourInst
Organizational Unit Name (eg, section) []:IT Team
Common Name (e.g. server FQDN orYOUR name) []:www.yourdomain.ws.learn.ac.lk
Email Address []:info@yourdomain.ws.learn.ac.lk

Once finished, it will create two files in /etc/ssl. Next create another apacheconfig fileas web1-ssl.conf and include

<IfModule mod_ssl.c>
    <VirtualHost _default_:443>
         ServerAdmin admin@yourdomain.ws.learn.ac.lk
         ServerName web1.yourdomain.ws.learn.ac.lk
         DocumentRoot /var/www/web1
         <Directory /var/www/web1>
                  Require all granted
         </Directory>
         ErrorLog ${APACHE_LOG_DIR}/error.log
         CustomLog ${APACHE_LOG_DIR}/access.log combined
         SSLEngine on
         SSLCertificateFile      /etc/ssl/certs/apache_crt.crt
         SSLCertificateKeyFile /etc/ssl/private/apache_prv.key
         <FilesMatch "\.(cgi|shtml|phtml|php)$">
                  SSLOptions +StdEnvVars
         </FilesMatch>
         <Directory /usr/lib/cgi-bin>
                  SSLOptions +StdEnvVars
         </Directory>
         </VirtualHost>
</IfModule>

Now enable this site by

sudo a2enmod ssl
sudo a2ensite web1-ssl.conf

Try browsing https://web1.yourdomain.ws.learn.ac.lk, you will be warned about the untrusted connection as it is a self-signed authentication.

Something Useful

Also as a best practice it is better to disable port 80 or plain HTTP traffic to your server. But if your directly disable Port 80 and allow only 443 then we have to manually type “https://” before your exact url in browsers. Therefore, better to redirect all HTTP traffic to port443 from your server configuration without disabling. So to do that we need to put a redirect in each virtual host conf. files.

Edit port 80 virtual host configuration files and add these in bottom just before the line </VirtualHost>

RewriteEngine on
RewriteCond %{SERVER_NAME} = web1.yourdomain.ws.learn.ac.lk
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
</VirtualHost>

Then enable mod-rewrite in apache and restart..

sudo a2enmod rewrite
sudo systemctl reload apache2

Now test your configuration by browsing to http://www.yourdomain.ws.learn.ac.lk and see how it redirects

http2

HTTP/2 support is included in Apache 2.4.17 and upwards. Enable HTTP/2 module by executing,

sudo a2enmod http2

then add below to each individual ssl virtual host files to enable respectively.

Protocols h2 http/1.1

To enable http/2 globally you can add following to the apache.conf

Protocols h2 h2c http/1.1

Once those lines are added restart apache and visit https://tools.keycdn.com/http2-test to check http2 configuration.

Enable ufw(Ubuntu Firewall)

Before enabling ufw we must allow all outdoing and deny all incoming traffic as default. Also allowing ssh will be a must.

sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow ssh

Then enable ufw,

sudo ufw enable

Press y when asked:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

and try to access your server from browser.

To enable port 80 and 443 we need,

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Check UFW status by

sudo ufw status
sudo ufw status verbose

Troubleshoot

systemctl status apache2.service
journalctl –xe

Log files:

tail –f /var/log/syslog
tail –f /var/log/apache2/access.log
tail –f /var/log/apache2/error.log

HTTPS configuration using Let’s Encrypt

Following are some additional stuff for you to try at your own institute with your own webserver and public IP addresses.

Prerequisites:To deploy Let’sEncrypt ssl certificates you must have public DNS and reachability from Internet

Install letsencrypt client on the server

sudo apt-get install python-letsencrypt-apache

Run the following to enable https for the selected domain specified with –d.

sudo letsencrypt --apache -d www.yourdomain.ws.learn.ac.lk

During the process you will be requested to enter a valid e-mail address where it will be used to send you details of your certificate and alerts like certificate expiry. Also you will be able to pick between enabling both http and https access or forcing all requests to redirect to https. It is usually safest to require https, except you have a specific necessity for unencrypted http traffic.
If you want to enable https for other domains, then run the above with the other domain names as well.

NOTE: If your put several domains in single command with multiple –d flags then all those sites will be issued single ssl certificate with multiple domain names. This is useful if you want to certify a specific server name and a parent domain both at the same time. (Eg. www.learn.ac.lk , learn.ac.lk both will end up in same landing page without generating errors.) Once letsencrypt finishes, go to https://www.ssllabs.com/ssltest/analyze.html?d=www.yourdomain.ws.learn.ac.lk&latest

and check https connectivity.

Auto Renewal of Certificates:

Let’s Encrypt certificates are normally valid for 90 days only. Therefore, we have to renew these certificates at least once every 3 months. This can be done automatically by creating a cron job in Linux to execute letsencript renew command. To edit cron Jobs

sudo crontab –e

then it will ask for an editor. To use nano the default editor press enter.

At the bottom of the page insert below and save/exit,

30 4 25 */2 * /usr/bin/letsencrypt renew >> /var/log/le-renew.log

Above command will execute “/usr/bin/letsencrypt renew” on 25 th day in every two months and will write the output to a file called “/var/log/le-renew.log”

Last modified 3 years ago Last modified on Nov 29, 2016, 6:45:29 PM