Sonntag, 22. März 2015

C# Chat Client v2

In diesem Post möchte ich eine etwas verbesserte Version des Chat Clients aus dem vorigen Post vorstellen, welche statt der Klasse mysql in PHP die Klasse mysqli verwendet und so durch Prepared Statements SQL-Injections verhindert.
Die PHP Skripte sehen nun so aus:

register.php (http://bloggeroliver.bplaced.net/Chat/Secure/register.php):

<?php
include("connect.php");

$username = $_POST["username"];
$password = $_POST["password"];
$hashedpw = md5($password);

$stmt = $conn->prepare("SELECT username FROM Users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();

$stmt->store_result();
$num_rows = $stmt->num_rows;

if ($num_rows > 0) {
     echo "Existing";
}
else {
     $stmt = $conn->prepare("INSERT INTO Users (username, password) VALUES (?, ?);");
     $stmt->bind_param("ss", $username, $hashedpw);
     $stmt->execute();
     echo "Success";
}
?>

login.php (http://bloggeroliver.bplaced.net/Chat/Secure/login.php):

<?php
session_start();

include("connect.php");

$username = $_POST["username"];
$password = $_POST["password"];
$hashedpw = md5($password);

$stmt = $conn->prepare("SELECT password FROM Users WHERE username = ? LIMIT 1");
$stmt->bind_param("s", $username);
$stmt->execute();

$stmt->bind_result($rowpassword);
$row = $stmt->fetch();

if($rowpassword == $hashedpw) {
    $_SESSION["username"] = $username;
    echo "LoginGood";
}
else {
    echo "LoginBad";
}
?>

send.php (http://bloggeroliver.bplaced.net/Chat/Secure/send.php):

<?php
session_start();

include("connect.php");

$Recipient = $_POST["Recipient"];
$Message = $_POST["Message"];
$Sender = $_SESSION['username'];

if(!isset($_SESSION['username'])) {
     echo "Login first.";
     exit;
}  

$stmt = $conn->prepare("INSERT INTO Messages () VALUES (?, ?, ?);");
$stmt->bind_param("sss", $Sender, $Recipient, $Message);
$stmt->execute();
    
?>

receive.php (http://bloggeroliver.bplaced.net/Chat/Secure/receive.php):

<?php

session_start();

include("connect.php");

if(!isset($_SESSION['username']))
   {
   echo "Bitte erst login";
   exit;
   }   
    
$Recipient = $_SESSION['username'];

$stmt = $conn->prepare("SELECT Sender, Message FROM Messages WHERE Recipient = ?");
$stmt->bind_param("s", $Recipient);
$stmt->execute();
    
$stmt->bind_result($sender, $message);
while($row = $stmt->fetch())
   {
          echo "$sender<br />";
          echo "$message<br />";
          $stmt->bind_result($sender, $message);
   }

$stmt = $conn->prepare("DELETE FROM Messages WHERE Recipient = ?");
$stmt->bind_param("s", $Recipient);
$stmt->execute();
?>

Im Code des C# Clients ist nur eine Zeile zu ändern, und zwar die Variable ServerUrl auf die Adresse des neuen Skriptordners: string ServerUrl = "http://bloggeroliver.bplaced.net/Chat/Secure/";

Der komplette Quellcode kann hier heruntergeladen werden, das fertige Chat Programm eingestellt auf meinen Server kann über diesen Link installiert werden.
Auch in diesem Chat heiße ich bloggeroliver und freue mich auf eure Nachrichten!

Nun möchte ich hier noch generell die Sicherheit dieses Chats diskuttieren. Im Wesentlichen sehe ich noch 2 Sicherheitslücken:

  • Das Passwort beim Login wird unverschlüsselt übertragen. Ein Angreifer, welcher Zugriff auf den Netzverkehr hat, könnte dieses auslesen oder sich einfach durch Schicken der gleichen Nachricht selber anmelden. Dieses Problem werde ich im nächsten Post angehen. Eine Möglichkeit wäre, die Verbindung z.B. durch TLS/SSL zu verschlüsseln. Dafür ist aber ein (eventuell kostenpflichtiges) Zertifikat nötig, ich möchte es gerne mit "C# Bordmitteln" lösen. Daher werde ich eine Challenge / Response Authentifizierung mit einem Public Key implementieren.
  • Außerdem werden die Nachrichten unverschlüsselt übertragen, es tritt das gleiche Problem wie oben auf, jeder Angreifer mit Zugriff auf den Netzverkehr könnte also mitlesen. Außerdem kann der Datenbankbetreiber alles lesen. Allerdings würde ich dieses nicht unbedingt als Sicherheitsproblem ansehen (und auch als wesentlich weniger gravierend als der erste Punkt), sondern als Feature. Falls keine Verschlüsselung der Nachrichten gewünscht ist, kann man dies so lassen (es ist nicht unbedingt die Sicherheit des Systems gefährdet, nur keine Vetraulichkeit gewährleistet), und ansonsten eine Verschlüsselung einsetzen (was aber natürlich empfohlen ist). Im übernächsten Post werde ich auch dieses mit einem Public Key Verfahren lösen.

Keine Kommentare:

Kommentar veröffentlichen