Search code examples
javascriptphpencryptionchatdata-integrity

How to protect chat messages from man in the middle (PHP, JavaScript)


I'm currently working on a chat system for my website. I'm no wondering how to protect the integrity of a message. I'm currently doing this via

chat.class.php

class Chat{
    private $config;
    private $randomJSONrpc;
    private $MySQL;

    function __construct($config = 'chat.config.json') {
        $this->config = $config;
        unset($config);
        if(file_exists($this->config)) {
            $config = json_decode(file_get_contents($this->config), false);
            $config->configfile = $this->config;
            $this->config = $config;
            unset($config);
        } else {
            $this->error('Configtest');
        }

        require_once 'jsonrpc.class.php';
        $jsonrpc = new JsonRpcClient('https://api.random.org/json-rpc/1/invoke');
        $this->randomJSONrpc = $jsonrpc;
        unset($jsonrpc);

        $this->MySQL = $this->database();
    }

    private function database() {
        if($this->config->salt == 'random') {
            $random = $this->random(8, 'string');
            $this->config->salt = $random;
            $file = $this->config->configfile;
            unset($this->config->configfile);
            file_put_contents($file, json_encode($this->config));
        } 
        $mysql_function = $this->config->drivers->mysql;
        if($mysql_function == 'mysqli') {
            $connection = new MySqLi($this->config->mysql->host, $this->config->mysql->user, $this->config->mysql->password, $this->config->mysql->database)or $this->error('MySQL connection', mysqli_error());
            return $connection;
        } else {
            error('MySQLi connection driver');
        }
    }

    public function hash($input, $algo = 'blowfish') {
        if($algo == 'blowfish') {
            $hash_algo = '$2a';
            $cost = '$10';
        } elseif($algo == 'md5') {
            $hash_algo = '$1';
            $cost = '';
        } else {
            $this->error('Algo availibility check', 'chat.class.php#class:Chat->hash('.$input.', '.$algo.')');
        }
        $salt = substr(sha1($this->config->salt),0,22);
        return crypt($input, $hash_algo.$cost.'$'.$salt);
    }

    public function random($length, $address = 'string') {
        $jsonrpc = $this->randomJSONrpc;
        if($address == 'string') {
            $params = new stdClass;
            $params->apiKey = $this->config->RANDOMapiKey;
            $params->n = 1;
            $params->length = $length;
            $params->characters = 'abcdefghijklmnopqrstuvwxyz1234567890';
            $params->replacement = true;
            $data = $jsonrpc->generateStrings($params);
            return $data->random->data[0];
        } else {
            $this->error('JSON-RPC address test');
        }
    }

    public function readNewMessages() {
        return 'dev.testing';
    }

    private function error($test, $extrainfo = false, $status = false) {
        if($status == false AND $extrainfo == false) {
            die($test.': <span style="color: red;">FAILED</span><br />'.PHP_EOL);
        } elseif($status != false AND $extrainfo == false) {
            echo $test.': <span style="color: green;">OK</span><br />'.PHP_EOL;
        } elseif($status == false AND $extrainfo != false) {
            die($test.': <span style="color: red;">FAILED('.$extrainfo.')</span><br />'.PHP_EOL);
        } elseif($status != false AND $extrainfo != false) {
            echo $test.': <span style="color: green;">OK('.$extrainfo.')</span><br />'.PHP_EOL;
        }
    }
}
?>

chat.php which should retrive new posts

<?php
header('Content-Type: application/json');
include 'chat.class.php';
$chat = new Chat();
if(session_id()) {
    session_close();
}

$i = 1;
$message = null;
while(!$message) {
    sleep(1);
    $data = $chat->readNewMessages();
    $i++;
}
$response = array('data' => $data, 'itnegrity' => //here I wondered how to save the integrity. );
echo json_encode($message);
?>

I have three things, I probably could use.

  1. MD5 Hashing my message
  2. Use SSL
  3. Encrypt the message via a client generated password which is send encrypted with the users password to the server and the message is sended back encrypted with the users password to.

The application is still in development and not working. I want to use Long Polling to retrive either a message or a heartbeat from the server.


Solution

  • Option #1 is not an answer in itself, anybody can hash, including attackers.

    A MITM can change the code on the client if SSL is not used. Just maybe you can exchange XML encoded messages (as in option #3) without SSL using Message Authentication Codes, but I wonder what you would gain over SSL; SSL is very likely to be more efficient and known secure.

    So in the end - as often is the case - you are left with SSL if the client is a browser. That would be option #2.