0

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.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
jankal
  • 1,090
  • 1
  • 11
  • 28
  • Why do you suspect that MitM attacks to be a likely scenario? – Pointy Nov 01 '14 at 21:05
  • I don't think that this is a likely scenario. But I want to build a 100% secure chat application. It's not good enough, if someone in the middle could edit the chat protocol to do something like phishing or click jacking. – jankal Nov 01 '14 at 21:07
  • Well MitM attacks are *extremely* hard to deal with, because by definition all communication is available to the attacker. A client has to log in to the service, and that inevitably exposes the password. – Pointy Nov 01 '14 at 21:12
  • Yes. But you could encrypt this to or even hash it on client side with md5 or sha256 or even blowfish how I am doing it on server side. – jankal Nov 01 '14 at 21:13
  • Hashing is irreversible, so that does you no good. Yes, you can hash the message, but then the text is not recoverable. If you want to encrypt it, there has to be a key exchange, and the attacker is privy to those communications too. – Pointy Nov 01 '14 at 21:20
  • 3
    2. Is the only way to go. 3. Is possible if the initial establishment of the key is done through SSL. – Artjom B. Nov 01 '14 at 21:27
  • Yes. But soemthing like this works with login. You can hash the password with md5 on client side and then hash it on serverside with blowfish. Then I normally send back a user-hash. Now the user is authentificated with the password which javascript stores in localStorage and the password which is also stored in localStorage. If the user is now doing a new request to the server, he must send a hash of the current timestamp+password-hash+user-hash. This will be checked on server side. This system is very complicated to exploit because there are so much parameters, which will influence the hashs. – jankal Nov 01 '14 at 21:30
  • @ArtjomB. Yes. The keys must intitially got exchanged over SSL. But then you must use something like getting the password from PHP via SSL and then I could communicate via HTTP normally. – jankal Nov 01 '14 at 21:32

1 Answers1

1

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.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263