Creating a Secure Website Login


In this session, our goal is to create a secure website login. The steps taken, to implement the project should be the pretty much the same for any Linux/UNIX system, except for a maybe a few minor file path or application manager differences. I myself will be working with a CentOS Linux system. We'll be making use of quite a few different technologies here...

In detail these are:

A MySQL database, which will hold the data of the login user.

Some HTML for the webpages themselves.

A little bit of CSS to style the pages.

PHP, to establish the database connection and perform the actual login via a session.

Some basic web server management with the Apache web server.


1. Install the Requirements:

First su to root and install a few requirements via yum. Depending on your operating system your package manager may be different from mine:

[user@localhost ~]$ su
Password: 
[root@localhost user]# yum install httpd openssl mysqld php mod_ssl

2. Setup the Database

Now we need to create the database and populate it with some data. Later we'll be using the information in this database to login to our site. Before we do so however, let's check if the mysqld binary is running, as otherwise we wouldn't be able to establish a connection to our database:

First let's check wether the mysql server mysqld is currently running:

[root@localhost user]# service mysqld status
mysqld is stopped
[root@localhost user]# service mysqld start
Starting mysqld:                                           [  OK  ]
[root@localhost user]# service mysqld status
mysqld (pid  6800) is running...

Next, let's make sure that mysqld is started each time the system boots:

[root@localhost user]# chkconfig | grep mysqld
mysqld         	0:off	1:off	2:off	3:off	4:off	5:off	6:off
[root@localhost user]# chkconfig mysqld on
[root@localhost user]# chkconfig | grep mysqld
mysqld         	0:off	1:off	2:on	3:on	4:on	5:on	6:off

Now we can connect to the database...

There are two tools that we can use in MySQL to create a database:

The mysqladmin binary or mysql command line interpreter: mysql. We'll be using the command line interpreter.

So let's log in to the database server as the default root user and first create:

a) a database that will hold our login data

b) a new database user and then

c) assign administrative privileges to that user

[user@localhost ~]$ mysql --user=root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.1.73 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
+--------------------+
2 rows in set (0.00 sec)

mysql> SELECT DATABASE();
+------------+
| database() |
+------------+
| NULL       |
+------------+
1 row in set (0.00 sec)

mysql> CREATE DATABASE login;
Query OK, 1 row affected (0.00 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| login              |
| mysql              |
+--------------------+
3 rows in set (0.00 sec)

mysql> select user, host, password from mysql.user;
+------+-----------------------+----------+
| user | host                  | password |
+------+-----------------------+----------+
| root | localhost             |          |
| root | localhost.localdomain |          |
| root | 127.0.0.1             |          |
|      | localhost             |          |
|      | localhost.localdomain |          |
+------+-----------------------+----------+
5 rows in set (0.00 sec)

mysql> CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.00 sec)

mysql> select user, host, password from mysql.user;
+------+-----------------------+-------------------------------------------+
| user | host                  | password                                  |
+------+-----------------------+-------------------------------------------+
| root | localhost             |                                           |
| root | localhost.localdomain |                                           |
| root | 127.0.0.1             |                                           |
|      | localhost             |                                           |
|      | localhost.localdomain |                                           |
| user | localhost             | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
+------+-----------------------+-------------------------------------------+
6 rows in set (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON login. * TO 'user'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> USE login;
Database changed
mysql> SHOW TABLES;
Empty set (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye

Now that we've created our login database as well as as another database user called user and assigned administrator privileges for that DB to him, we'll login to the mysql server yet again. This time around, we'll login as user and populate the database with login credentials. These will subsequently be used, when login in via our html webpage as outlined down below...

[user@localhost ~]$ mysql --user=user --password=password login
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.1.73 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT USER();
+----------------+
| USER()         |
+----------------+
| user@localhost |
+----------------+
1 row in set (0.00 sec)

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| login      |
+------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE users (
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> user VARCHAR(50) NOT NULL UNIQUE,
    -> password VARCHAR(50) NOT NULL
    -> );
Query OK, 0 rows affected (0.10 sec)

Now we insert a record into our users table along with a password:

mysql> INSERT INTO users (user, password) VALUES('user', MD5('secret'));
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * from users;
+----+------+----------------------------------+
| id | user | password                         |
+----+------+----------------------------------+
|  1 | user | 5ebe2294ecd0e0f08eab7690d2a6ee69 |
+----+------+----------------------------------+
1 row in set (0.00 sec)

mysql> exit
Bye

As you can see, the user we created is called user along with the password secret, which has been stored as its MD5 value. We are now ready to move on to the next step...

3. Setting up Apache

Let's make sure, that the apache server httpd is up and running:

[root@localhost user]# service httpd status
httpd is stopped
[root@localhost user]# service httpd start
Starting httpd:                                           [  OK  ]
[root@localhost user]# service mysqld status
httpd (pid  2736) is running...

Furthermore, make it available every time the system starts up:

[root@localhost user]# chkconfig | grep httpd
httpd         	0:off	1:off	2:off	3:off	4:off	5:off	6:off
[root@localhost user]# chkconfig httpd on
[root@localhost user]# chkconfig | grep httpd
httpd         	0:off	1:off	2:on	3:on	4:on	5:on	6:off

Your actual sites will sit here:

/var/www/html/

Apache's configfiles reside in:

/etc/httpd/conf


4. Implementing the Code

We'll need four pages all in all:

1. The Login Page

2. A PHP script that checks our login against our database

3. The Protected Area - The Page that we are logged in to

4. A Logout Page


We'll style both of the pages that are visible to the user with some basic Cascading Style Sheets - CSS.

4.1 Create the HTML page

<?php
	session_start();
        if(isset($_SESSION['loggedin']))
              header("protected.php");
?>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<form action="login.php" method="post">
Username:<input type="text" name="username" />
Password:<input type="password" name="password" />
<input type="submit" value="Login" />
</form>
</body>
</html>

The result of which should look like this:

...

3 Things to note here:

1. At the beginning of the page we initiate a PHP session.

2. We use CSS to style the page

3. The rest is just plain old school HTML


4.2 The Check login script

This script called, check_login.php, serves to receives the data we put into the form, opens a connection to our MySQL database via PDO and checks, whether the data we entered is reasonable, i.e. whether or not the users exists and the password is correct. Supposing that the data we entered is valid, we are granted access. We furthermore set a session variable, that allows us, easier access when leaving the page and logging in again later. If the data entered is not correct, we are returned back to the login page. The page itself is not visible to the user.

// This page is jumped to, once the user hits the login button.
// It open the database and checks wether the users exists.
// Supposing he does exist, the user may enter the protected area.
// If he doesn't exist in the db then, the user is sent back 
// to the login page.

<?php
	session_start();
        if(isset($_SESSION['loggedin']))
              header("protected.php");

        // This information is required to login to the database
        db_host = localhost;
        db_name = login;
        db_user = user;
        db_pass = password;

	// from form
        username = $_POST['username'];
        password = $_POST['password'];

        if(empty($_POST["username"]) || empty($_POST["password"])) {
               header("");
               exit();  
        }

// get md5 hash of $password
	$password = md5($password);

	// open database connection
        $pdo = database_connection($db_host, $db_name, $db_user, $db_pass);     

        /* query */
        $result = check_login($u_name, $p_word_md5, $pdo);

	if($result == 1) { /* we have a match */                       

                /* set a session variables */
                $_SESSION['loggedin'] = 'TRUE'; // logged in

		/* close the database connection */
		$pdo = null;  

                /* and redirect */
                header("");
	} /* if */
	else { /* wrong credentials */

		/* close the database connection */                
                $pdo = null;

                /* and go back to the login page */ 
		header("login.php");
	} /* else */
?>

4.3 The Protected Area

The following page, protected.php is the page that we jump to, when logging in. Here we can put all the stuff, that is not meant for the general public.

<?php
	session_start();
        if(!isset($_SESSION['loggedin']))
              header("login.php");
?>
<html>
<head>
<title>Protected Area</title>
</head>
<body>
<p>
This is the protected area.
</p>
<p>
To logout click here: <a href="logout.php"p>LOGOUT</ap>
</p>
</body>
</html>


4.4 The Logout page



<?php
        sessions_start();
	session_destroy();
        unset($_SESSION['loggedin']);
        header("");
?>



5. Implement an SSL key

/etc/httpd/conf.d/ssl.conf

SSLCertificateFile /etc/pki/tls/certs/testcom.crt

/etc/pki/tls/certs/

/etc/pki/tls/private/

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout examplecom.key \ -out examplecom.crt



The user is required to answer a few questions.

3. Location of the key and certificate files:

# cp -iv examplecom.key /etc/pki/tls/private

# cp -iv examplecom.crt /etc/pki/tls/certs

References:

The PHP PDO Manual

PHP Session Reference

Another PDO Tutorial

MySQL Documentation