Datensätze verschlüsselt in Datenbank speichern

Bei 99points.info habe ich heute eine Klasse gefunden, die von ZeeShaN dort gepostet wurde. Dies PHP-Class ist zum sicheren ver- und entschlüsseln von Daten gedacht.

Eine gute Gelegenheit, mal ein kleines Script zu schreiben, in dem ich zeige, wie man Daten aus einem Html-Formular verschlüsselt in eine MySQL-Datenbank ablegen und diese anschließend aus der Datenbank auslesen und wieder entschlüsselt anzeigen lassen kann.

Hier zuerst einmal der Inhalt der Datei db.inc.php, welche im Verzeichnis inc liegt. Diese Datei muss eingebunden werden bevor mit der Datenbank gearbeitet werden soll, da diese die Verbindung zur Datenbank herstellt. Die Zugangsdaten müssen Sie natürlich vorher noch anpassen. Ich benutze zum testen meiner Scripts einen lokalen Server, weshalb hier die Zugangsdaten für zwei Datenbanken angegeben werden.

inc/db.inc.php

<?php
if($_SERVER['SERVER_PORT'] == '8888')
{ //local
	define('DB_SERVER',"localhost");
	define('DB_NAME',"DATENBANKNAME");
	define('DB_USER',"DATENBANKUSER");
	define('DB_PASSWORD',"DATENBANKPASSWORT");
}
else
{ //remote
	define('DB_SERVER',"SERVER");
	define('DB_NAME',"DATENBANKNAME");
	define('DB_USER',"DATENBANKUSER");
	define('DB_PASSWORD',"DATENBANKPASSWORT");
}

$conn = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD);
if(is_resource($conn))
{
	mysql_select_db(DB_NAME, $conn);
	mysql_query("SET NAMES 'latin1_german1_ci'", $conn);
}
?>

 

index.php

<?
//Sicheres Passwort das zum verschlüsseln der Daten genutzt wird
define("PASSPHRASE", "4x,bj]8c92v7/#Nt4P[3V3nUKqo6fg");

//Verbindungsdaten zur MySQL-Datenbank
include_once('inc/db.inc.php');

//Klasse zum ver- und entschlüsseln von Daten
class Encryption {
	var $skey = PASSPHRASE;

    public  function safe_b64encode($string) {

        $data = base64_encode($string);
        $data = str_replace(array('+','/','='),array('-','_',''),$data);
        return $data;
    }

	public function safe_b64decode($string) {
        $data = str_replace(array('-','_'),array('+','/'),$string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    public  function encode($value){ 

	    if(!$value){return false;}
        $text = $value;
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
        return trim($this->safe_b64encode($crypttext)); 
    }

    public function decode($value){

        if(!$value){return false;}
        $crypttext = $this->safe_b64decode($value); 
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
        return trim($decrypttext);
    }
}

//Daten nach abschicken des Formulars in Datenbank speichern
if(isset($_POST['MM_SUBMIT']) && $_POST['MM_SUBMIT'] == "Speichern")
{
  $ERRORMESSAGE = "";

  $nachname = trim(mysql_real_escape_string($_POST['nachname']));
  $vorname  = trim(mysql_real_escape_string($_POST['vorname']));

  //Test ob Daten in die Pflichtfelder eingegeben wurden
  if(empty($nachname)) { $ERROR=1; $ERRORMESSAGE .= "Es wurde kein Nachname eingegeben!<br />"; }
  if(empty($vorname))  { $ERROR=1; $ERRORMESSAGE .= "Es wurde kein Vorname eingegeben!<br />"; }

  if(!isset($ERROR))
  {
    //Nachname und Vorname aus dem Formular verschlüsseln
    $Encrypt = new Encryption();

    $nachname = $Encrypt->encode($nachname);
    $vorname  = $Encrypt->encode($vorname);

    //Verschlüsselte Daten in die Datenbank eintragen
    $q_data = mysql_query("INSERT INTO kunden (Nachname, Vorname) VALUES ('".$nachname."', '".$vorname."')") or die(mysql_error());
    if($q_data > 0)
    {
      header("Location: test.php"); //Seite neu aufrufen wenn Daten in die Datenbank geschrieben werden konnten
    }
    else
    {
      $ERRORMESSAGE .= "Die Daten konnten nicht in der Datenbank gespeichert werden!<br />";
    }
  }
} 
?>
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=windows-1252" />
  <title></title>
<style type="text/css" media="all">
  .fl {
    width: 120px;
    float: left;  
  }

  .frm {
    background: yellow;
    padding: 10px;
    width: 300px;
    border: 10px solid #eee;
  }

  .c1 {
    background: #eee;
  }

  .c2 {
    background: #ccc;
    font-weight: bold;
  }
  </style>
</head>
<body>
<?
  //Wenn Fehler aufgetreten sind, diese hier ausgeben
  if(isset($ERROR)) echo "<div style=\"background: red; color: white; padding: 10px; margin-bottom: 20px;\">".$ERRORMESSAGE."</div>";
?>
<!-- Formular zur Eingabe neuer Daten -->
<h3>Neue Daten in Datenbank eintragen</h3>
<form class="frm" name="form1" method="post">
  <div class="fl">Nachname:</div><input type="text" name="nachname" value="<? if(isset($_POST['nachname'])) echo $_POST['nachname'];?>"><br />
  <div class="fl">Vorname:</div><input type="tel" name="vorname" value="<? if(isset($_POST['vorname'])) echo $_POST['vorname'];?>"><br />
  <div class="fl"> </div><input type="submit" name="MM_SUBMIT" value="Speichern">  
</form>

<p style="clear: both; padding-bottom: 50px;"></p>

<!-- Ausgabe der verschlüsselten Daten aus der Datenbank, daneben die Daten aus der Datenbank entschlüsselt -->
<table border="1" cellpadding="4" cellspacing="0">
  <tr class="c1">
    <td colspan="2">Verschlüsselte Daten in der Datenbank</td>
    <td colspan="2">Daten aus der Datenbank entschlüsselt</td>
  </tr>
  <tr class="c2">
    <td>Vorname:</td><td>Nachname:</td>
    <td>Vorname:</td><td>Nachname:</td>
  </tr>
<?
  $Encrypt = new Encryption();

  $q_data = mysql_query("SELECT Vorname, Nachname FROM Kunden WHERE KundenNr = 0 ORDER BY Nachname DESC");
  while($r_data = mysql_fetch_object($q_data))
  {
    echo "<tr>\n";
    echo "  <td>".$r_data->Vorname."</td><td>".$r_data->Nachname."</td>\n"; 
    echo "  <td>".$Encrypt->decode($r_data->Vorname)."</td><td>".$Encrypt->decode($r_data->Nachname)."</td>\n";
    echo "</tr>\n";
  }
?>
</table>

</body>
</html>

ACHTUNG:
Das in PASSPHRASE definierte Passwort sollte man weder weitergeben noch nachträglich ändern, da sich sonst die zuvor verschlüsselten Daten nicht mehr entschlüsseln lassen.

Ich denke dass dies ein äußerst praktisches Beispiel ist, wie man ohne viel Mühe, sensible Daten in der Datenbank sichern kann. Wer Anregungen oder Verbesserungsvorschläge hat, postet diese bitte als Kommentar zu diesem Beitrag.

Über Enrico S.

Programmierer, Webdesigner, Grafiker, Blogger, Screencaster, Arduino- und eMobility Enthusiast.

2 Kommentare zu “Datensätze verschlüsselt in Datenbank speichern

  1. Hi,

    auch hierzu meine Meinung !
    Ich finde die Variante wirklich Gut!

    Mir kommt da allerdings ein Gedanke.
    Wenn ich zum Beispiel dies auf die Kundendaten eines OnlineShops anwende, dann würde ich mir wünschen, dass das Passwort „nicht“ in der INDEX.php steht.
    Hintergrund ist, dass es in den letzten zwei Jahren sehr oft vorgekommen ist, dass XTcommerce und Forks gehackt wurden.

    Eine Art …

    define(„PASSPHRASE“, „http://mein_anderer_server.com/xx/xx/kennwort.txt“);

    SERVER-II …
    [htaccess] IP vom Server I
    Verzeichnis xx/xx/kennwort.php

    kennwort.txt
    4x,bj]8c92v7/#Nt4P[3V3nUKqo6fg

    Das wäre der Hit.
    Denn wenn der Shop gehackt wird und der Hacker feststellt, dass der PASSPHRASE auf einem anderen Server hinterlegt ist, muss er diesen auch noch knacken. Um das dann auch noch zu erschweren eine htaccess für das Verzeichnis erstellen, welche nur Computer für die Abfrage mit einer bestimmten IP Zugriff auf das Verzeichnis gewährt, ist dies wohl ein Mega Aufwand.

    Würde das laufen und viel langsamer dürfte das System ja nicht werden – WENN der Server-II nicht down ist > Smiley < !?

    MfG Thomas Berger

    • Gute Idee von Dir.
      Man könnte die Passphrase aber auch direkt in der Datenbank ablegen, dort eventuell sogar noch als sha1 hash.
      Wie immer gibt es so viele Möglichkeiten und jeder muss selber wissen welchen Aufwand er bereit ist auf sich zu nehmen.
      Es kommt ja auch immer auf die Art des Projektes an. Ich kann natürlich kein großes onlineshop-Projekt mit einem Blog gleichstellen.

      Aber schön dass sich auch mal einer Gedanken macht, diese hier veröffentlicht und nicht alles eins zu eins übernimmt.