Skip to content
No description, website, or topics provided.
PHP JavaScript CSS HTML
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.

Files

Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
app
public
.gitignore
README.md
composer.json
composer.lock

README.md

Project 04: Building a secure messaging system

In this project, I've extended the set of features for the secure login website to include messaging.

The website is being hosted on cmpsec.johnbojorquez.com.

The website supports single-recipient messages between users. All messages are sent over an SSL connection between the client and the server. Messages are also encrypted before they are stored in the database.

Database schema

To create the application's database, messages table, users table, and initial users we can run

php app\database\init.php

in the application directory.

The database initialization script in this project will create a messages table. The scheme of the messages table is as follows:

Field Type Null Key Default Extra
id int(10) unsigned NO PRI NULL auto_increment
message text NO NULL none
sender_id int(10) unsigned NO MUL NULL none
receiver_id int(10) unsigned NO MUL NULL none
enc_keys varchar(64) NO NULL none
keys_iv varchar(24) NO NULL none
message_iv varchar(24) NO NULL none

This project makes use of the MVC design pattern and new messages are inserted into the database as follows:

$m = new SecureMessage;
$m->message = "Hello, world!";
$m->sender_id = 1;
$m->receiver_id = 2;
$m->save();

It's important to notice that the SecureMessage::save() method will encrypt the message prior to inserting into the messages table;

The SecureMessage class also supports several static methods for retrieving users from the users table in the form of a User object.

Protecting the contents of the messages table

The goal of this project is to devise a strategy for securely storing messages on the server. This is done by encrypting the messages before storing them in the messages table. I have adopted the following strategy. When a user submits a message to be "sent" to another user, two 16-byte keys are generated:

$integrity_key = openssl_random_pseudo_bytes(16);
$encryption_key = openssl_random_pseudo_bytes(16);

A 64-byte keyed hash is generated using the SHA256 hashing algorithm:

$message_hash = hash_hmac(Config::hash_algo, $this->message, $integrity_key);

This hash is stored in the database to protect the integrity of the message. That is, any unauthorized changes to the message itself can be easily detected. Next, we generate a random 16-byte IV and encrypt the message and its hash using the AES-128-CBC encryption algorithm.

$message_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(Config::encr_algo));
$ciphertext = openssl_encrypt($this->message . $message_hash, Config::encr_algo, $encryption_key, 0, $message_iv);

Lastly, the keys are encrypted using a secret 16-byte key stored on the server.

$keys_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(Config::encr_algo));
$enc_keys = openssl_encrypt($integrity_key . $encryption_key, Config::encr_algo, Config::secret_key, 0, $keys_iv);

To retrieve a message from the database, its keys are decrypted using the system key. Then the message itself is decrypted using its own key.

Detecting changes to the contents of a message

When retrieving entries from the messages table, the hash is recomputed by hashing the message content using the integrity key, the produced hash is then compared with the hash that is stored in the database. If the hashes differ, the message has been altered and is thus discarded.

Protection against man-in-the-middle attacks

To ensure that the communication between the client and the server is protected, apache has been configured to used HTTPS (with the SSL protocol) for all communication. Using HTTPS requires the exchange of an SSL certificate. For the purpose of this project, a self-signed certificate was generated and stored on the server. This will ensure that all communication between the user's browser and the server is securely encrypted using public key encryption.

The downside of using a self-signed certificate is that the HTTPS connection, although encrypted, does not appear as a secure connection to the user's browser. This is because the certificate is not signed by a trusted authority. Although this still prevents against man-in-the-middle attacks with exchanging sensitive user-related information after the SSL handshake, this still opens the possibility of a man-in-the-middle attack during the handshake. There is no way for the user's browser to prevent attackers from providing their own certificate and tricking the user into giving the attacker their account login information. The solution to this problem is to purchase a signed certificate from a trusted authority.

You can’t perform that action at this time.