[C#/.NET] Verschiedene Authentifizierungsmöglichkeiten #1 – Plain
[C#/.NET] Verschiedene Authentifizierungsmöglichkeiten #2 – Verschlüsselung und SecureString

Eine Authentifizierung mittels MySQL ist ziemlich einfach und schnell geschrieben.

Wir müssen lediglich den .NET Connector für MySQL herunterladen, den Verweis auf die DLL hinzufügen und folgenden Namespace mittels

using MySql.Data.MySqlClient;

einbinden.

Nun benötigen wir ein Objekt der MySQLConnection, welches den ConnectionString beinhaltete und eine Verbindung zum MySQL-Server bereitstellt.

Ich erstelle ein Field vom Typ MySQLConnection (also eine Variable, auf welche alle Methoden innerhalb der Klasse zugreifen können), welches jedoch noch nicht initialisiert wurde.

MySqlConnection connection = null;

In der öffentlichen Methode setupConnection() erstelle ich den ConnectionString (mit den Parametern) und initialisiere den MySQLConnector mit dem ConnectionString.

public void setupConnection(string server, string database, string user, string password)
{
     string myConnectionString = "SERVER=" + server + ";" +
     "DATABASE=" + database + ";" +
     "UID=" + user + ";" +
     "PASSWORD=" + password + ";";
     connection = new MySqlConnection(myConnectionString);
}

Nun erstelle ich eine weitere öffentliche Methode, welche zur Authentifizierung dient.

public bool? Authenticate(string username, string password, string table) //Das Fragezeichen (?) nach einem Typ gibt an, dass der <a href="http://msdn.microsoft.com/de-de/library/1t3y8s4s(v=vs.90).aspx" target="_blank">Typ NULL-Werte zulässt (nullable)</a>
{
	try
	{
		MySqlCommand command = connection.CreateCommand();
		command.CommandText = "SELECT * FROM "+ table +" WHERE Username=?Username"; //Erstellt die parametrisierte Abfrage (Tabellen können nicht parameterisiert werden)
		command.Parameters.AddWithValue("?Username", username); //Weißt dem Parameter einen Wert zu
		MySqlDataReader Reader;
		connection.Open(); //Öffnet die Verbindung zum Server
		Reader = command.ExecuteReader(); Führt die Abfrage auf dem Server aus
		while (Reader.Read()) //Solange noch Daten verfügbar sind
		{
			if (Reader[1].ToString() == username) //Prüfe ob der Wert der ZWEITEN(!) Spalte mit dem übergebenen Usernamen übereinstimmt
			{ //Falls dies der Fall ist,
				if (Reader[2].ToString() == password)//prüfe ob der Wert der dritten Spalte mit dem Passwort übereinstimmt
				{//Sollte dem so sein,
					connection.Close(); //so schließe die Verbindung
					return true; //und geben den Wahrheitswert "wahr" zurück
				}
			}
		}
                //Sollten die Parameter nicht mit den Daten aus der DB übereingestimmt haben
		connection.Close(); //So schließe die Verbindung
		return false; //Und geben "false" zurück
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
		connection.Close();
		return null;
	}
}

Hashing

Nun ist es natürlich äußerst fahrlässig Passwörter klar in der Datenbank zu hinterlegen. Im besten Fall soll es unmöglich sein, das Passwort wieder im Klartext aus der Datenbank zu beziehen und genau hier wird Hashing genutzt. Im Gegensatz zur Verschlüsselung ist es dabei nicht mehr möglich das gehashte Passwort in das ursprüngliche zurückzuwandeln.
Es gibt ziemlich viele Hashfunktionen, zwei der Bekanntesten sind MD5 und SHA.

MD5
SHA-2
Vorteile
Nachteile
Vorteile
Nachteile
Schnell
Nicht kollisionsresistent
Bisher nicht geknackt
Langsamer als MD5
Viele Regenbogentabellen
Gilt als kollisionsresistent

Die Schnelligkeit beider Hashfunktionen ist aber auch eine der größten Schwächen in Bezug auf die Sicherheit des Passworts. So ist heutzutage möglich ein 8-stelliges Passwort, bestehend aus Zahlen und Buchstaben, gehasht mit SHA-2 GPU-gestützt innerhalb eines Tages zu knacken.

MD5

Nun aber zur Implementierung einer MD5-Hashfunktion mit C# und dem .NET-Framework. Dazu verwenden wir die MD5CryptoSerivceProvider-Klasse

public string CreateMD5Hash(string unhashedString)
{
	if (String.IsNullOrEmpty(unhashedString))
		return string.Empty;

	MD5 md5 = new MD5CryptoServiceProvider(); //Alternativ kann man auch MD5 md5 = MD5.Create(); verwenden
        //Create() initalisiert MD5CryptoServiceProvider, da MD5CryptoServiceProvider MD5 implementiert. MD5 ist eine abstrakte Klasse
	byte[] unhashedByteArray = Encoding.Default.GetBytes(unhashedString);
	byte[] result = md5.ComputeHash(unhashedByteArray);

	return System.BitConverter.ToString(result).ToLower().Replace("-", "");
}

SHA-2

Beinahe den selben Code kann man für SHA-2 verwenden. Statt dem MD5CryptoServiceProvider verwenden wir die SHA256CryptoServiceProvider-Klasse

public string CreateSHA2Hash(string unhashedString)
{
	if (String.IsNullOrEmpty(unhashedString))
		return string.Empty;

	SHA256 sha2 = new SHA256CryptoServiceProvider();
	byte[] unhashedByteArray = Encoding.Default.GetBytes(unhashedString);
	byte[] result = sha2.ComputeHash(unhashedByteArray);

	return System.BitConverter.ToString(result).ToLower().Replace("-", "");
}

Und jetzt haben wir eine Todsünde begangen. Das Hashes sind nicht gesalzen und können somit einfach per Rainbow Tables geknackt werden.

Salted MD5

Genau für diesen Zweck wurde HMAC entwickelt. Ein Implementierung in das .NET-Framework erfolgte mit der HMACMD5-Klasse

public string CreateSaltedMD5Hash(string unhashedString, byte[] key)
{
	HMACMD5 saltedMD5 = new HMACMD5();

	saltedMD5.Key = key;

	byte[] unhashedByteArray = Encoding.Default.GetBytes(unhashedString);
	byte[] result = saltedMD5.ComputeHash(unhashedByteArray);

	return System.BitConverter.ToString(result).ToLower().Replace("-", "");
}

Salted SHA-2

Für SHA2 gibt es die HMACSHA256-Klasse

public string CreateSaltedSHA2Hash(string unhashedString, byte[] key)
{
	HMACSHA256 saltedSHA2 = new HMACSHA256();

	saltedSHA2.Key = key;
	byte[] unhashedByteArray = Encoding.Default.GetBytes(unhashedString);
	byte[] result = saltedSHA2.ComputeHash(unhashedByteArray);

	return System.BitConverter.ToString(result).ToLower().Replace("-", "");
}

Wie ich oben bereits erwähnt habe, ist die Geschwindigkeit die größte Schwäche dieser Algorithmen. Darum sollte man MD5 und SHA auch mit Salt nicht zum Hashen von Passwörtern verwenden (MD5 und SHA dienen zur Berechnung einer eindeutigen Prüfsumme, nicht zum Hashen von Passwörtern). Für diesen Zweck wurden langsamere Algorithmen entwickelt, welche generell für das Verschlüsseln von Passwörtern verwendet werden sollten.  Die Bekanntesten sind PBKDF2 und bcrypt.

Zu guter Letzt das Demo-Projekt:

20130811_Verweis-Manager - OleDBTest_000034

MySQL_Hash.zip