© DrHitch/Shutterstock.com
Einblicke in C# 6.0

4 Sicherheit von C# 6.0


C# 6.0 ist da. Ebenso Visual Studio 2015 und .NET 4.6. Und auch, wenn C# 6.0 keine sicherheitsrelevanten Änderungen enthält, gibt es Neuigkeiten rund um die Sicherheit.

Fangen wir mit C# 6.0 an. Es gibt darin keine explizit sicherheitsrelevanten Änderungen. Trotzdem können sich einige der neuen Features [1] positiv auf die Sicherheit auswirken.

Nehmen wir zum Beispiel die Getter-only Auto-Properties [2]. Microsoft schreibt dazu: „This is about expressing types more concisely, but note that it also removes an important difference in the language between mutable and immutable types: auto-properties were a shorthand available only if you were willing to make your class mutable, and so the temptation to default to that was great. Now, with getter-only auto-properties, the playing field has been leveled between mutable and immutable.“

Ich würde das etwas anders formulieren: Jetzt müssen Klassen nur noch dann veränderbar sein, wenn das wirklich nötig und erwünscht ist. Was die Gefahr unerwünschter Manipulationen reduziert. Die waren zuvor bei den zwangsweise änderbaren Klassen zumindest theoretisch möglich, wenn man Auto-Properties verwenden wollte. Ob diese Möglichkeit in der Vergangenheit für Angriffe ausgenutzt wurde, ist dem Autor nicht bekannt. Aber eine Schwachstelle wird ja nicht erst gefährlich, wenn sie auch ausgenutzt wird. Allein die Möglichkeit eines Angriffs ist schon Grund genug, sie zu schließen.

Oder eben in diesem Fall, die Angriffsfläche zu reduzieren, denn darauf läuft es ja hinaus. Ist nur ein lesender Zugriff möglich, kann ein Angreifer maximal Informationen ausspähen, aber nichts manipulieren.

Außerdem erleichtert die Möglichkeit der Getter-only Auto-Properties die Einhaltung des Grundsatzes „Secure by Design“ bzw. „Secure by Implementation“ des Secure Development Lifecycle [3]. Denn nun ist es möglich, ohnehin nur lesend genutzte Werte auch wirklich „read-only“ zu implementieren. Wie es ja auch die .NET-Standards empfehlen.

Die nächste Verbesserung sind in meinen Augen die Null-conditional Operators [4]. Damit werden etliche separate Nullprüfungen gespart, und der Code wird lesbarer. Und je lesbarer der Code ist, desto leichter lässt er sich verstehen und desto leichter wiederum lassen sich Fehler darin aufspüren. Und damit auch mögliche Schwachstellen, denn das sind ja nur Fehler, die sich für Angriffe ausnutzen lassen. Aus so etwas wie zum Beispiel

var roleName = userManager.CurrentUser == null ? null : 
(userManager.CurrentUser.GetRole() == null ? null :
userManager.CurrentUser.GetRole().Name);

wird dank des neuen ?-Operators kurz

var roleName = userManager.CurrentUser?.GetRole()?.Name;

roleName wird dann zu Null, wenn CurrentUser, GetRole() oder Name Null ist. Der Code wird kürzer und die Bedeutung sofort klar. Nebenbei wird auch noch ein Aufruf von GetRole() eingespart.

Was passiert, wenn Code nicht leicht lesbar ist, hat Apple voriges Jahr mit der „GOTO FAIL“-Schwachstelle in der SSL-Implementierung von iOS und Mac OS X bewiesen [5]. Der Code enthält etliche Prüfungen nach dem Muster

if ((err = irgendwas) != 0)
goto fail;

und an einer Stelle eine zusätzliche goto fail;-Zeile. Die führte dazu, dass die Signatur des ausgetauschten SSL-Sitzungsschlüssels gar nicht erst geprüft wurde.

Ein Filter für Exceptions

Auch die Filter für Exceptions gefallen mir [6]. Die machen es leichter, auf verschiedene Situationen angemessen zu reagieren. Und lassen außerdem den Stack unverändert, sodass im Ernstfall in einem Dump die Daten der tatsächlichen Auslösung der Exception enthalten sind und nicht nur die des erneuten Versuchs, wie beim bisher üblichen „Catch and Re-Try“.

Nehmen wir als Beispiel Code, der eine SQL Exception auslösen kann, auf die gezielt reagiert werden soll, während ansonsten die Exception ihren normalen Lauf nimmt. Das könnte dann so wie in Listing 4.1 aussehen.

try { ... }
catch (Exception e) if ( e.GetType() == typeof(SqlException) )
{
// gezielt auf diese Exception reagieren,
// zum Beispiel die SQL-Abfrage ändern und es erneut probieren
}
// ansonsten nimmt die Exception ihren normalen Lauf

Listing 4.1

Oder vielleicht möchten Sie ja auch auf verschiedene Möglichkeiten einer Exception unterschiedlich reagieren. Das könnte zum Beispiel so wie in Listing 4.2 aussehen.

int fehlercode = 0;
try
{
// irgendetwas tun und dabei den Fehlercode je nach Fehler passend
// setzen
throw new InvalidOperationException();
}
catch (InvalidOperationException) when (fehlercode == 1)
{
// Der Fehler ist unschön, aber nicht kritisch.
// Den Fehler protokollieren
// und versuchen, den Code weiter auszuführen
}
catch (InvalidOperationException) when (fehlercode == 2)
{
// Der Benutzer hat was falsch gemacht.
// Fehlermeldung an den Benutzer ausgeben,
// neue Eingaben abwarten
// und versuchen, den Code weiter auszuführen
}
catch (InvalidOperationException) when (fehlercode == 3)
{
// Der Fehler lässt sich nicht reparieren
// Den Abbruch der Aktion an den Benutzer melden
// und die Aktion kontrolliert beenden
}
catch
{
// Das war jetzt wirklich unerwartet ...
}

Listing 4.2

Der Filter kann auch zweckentfremdet werden, um zum Beispiel in einer Hilfsfunktion ein Logfile zu aktualisieren (oder was auch immer parallel zur Exception zu erledigen ist), ohne den eigentlichen Ablauf der Exception zu behindern (Listing 4.3).

private static bool Log(Exception e) { 
// Vorfall protokollieren, danach FALSE zurückliefern
return false;
}
...
try { ... }
catch (Exception e) when (Log(e)) {}

Listing 4.3

Kommen wir zum Umfeld ...

C# ist ja „nur“ eine Programmiersprache. Für die Entwicklung von Software braucht man im Allgemeinen noch ein bisschen mehr. Ohne Entwicklungsumgebung (oder zumindest Editor, Compiler un...

Neugierig geworden?

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang