Das gibt es Neues rund um die Sicherheit von C# 6

Wie sicher ist C#6?
1 Kommentar

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

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

Nehmen wir zum Beispiel die Getter-only Auto-Properties. 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 [1]. 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. 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. 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. 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 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

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

int fehlercode = 0;
try
{
  // irgend etwas 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...
}

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 3).

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

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 und Linker) hat man von der Sprache nicht viel, und meist ist auch eine Laufzeitumgebung hilfreich. Von so etwas wie Bibliotheken mit fertigen Funktionen ganz zu schweigen. Und mit denen fange ich gleich einmal an, denn in .NET 2015 mit dem .NET Framework 4.6 sind einige sicherheitsrelevante Änderungen enthalten.

Neues in ASP.NET

Los geht es mit ASP.NET. Das enthält nun das von Microsoft und Google gemeinsam entwickelte Token Binding Protocol. Das ist ein neuer Ansatz zur Authentifizierung, der das leidige Problem des Missbrauchs im Browser ausgespähter Authentifizierungstoken lösen soll. Der Nachteil des neuen Protokolls: Es ist zumindest vorerst eine Insellösung, die Authentifizierungstoken müssen also zusätzlich weiterhin mit den altbekannten Schutzmaßnahmen wie dem Binden an die IP-Adresse oder Ähnlichem geschützt werden, damit Benutzer von Systemen und/oder Browser, die das Protokoll nicht unterstützen, nicht gefährdet werden.

Außerdem wird der bereits im .NET Framework 4.5 enthaltene Randomized String Hash Algorithm nun von ASP.NET unterstützt. Damit ist es möglich, die Hash-Werte pro Anwendung individuell zu berechnen. Gleiche Strings ergeben damit bei unterschiedlichen Anwendungen unterschiedliche und nicht wie im Normalfall identische Hash-Werte.

Neues in ADO.NET

ADO.NET unterstützt nun das mit der SQL Server 2016 Community Technology Preview 2 (CTP2) eingeführte Always-Encrypted-Feature. Dabei arbeitet der SQL Server mit verschlüsselten Daten, der verwendete Schlüssel wird innerhalb der Anwendung auf dem Clientrechner des Benutzers und nicht auf dem Server gespeichert. Die Ver- und Entschlüsselung erfolgt transparent auf Treiberebene, sodass kaum Anpassungen an vorhandene Anwendungen nötig sind.

Neues in den Basisklassen

Es gibt etliche Änderungen an den Basisklassen, von denen eine hier besonders relevant ist: Das System.Security.Cryptography-API unterstützt nun die Windows-CNG-Krypto-APIs und damit Microsofts aktuelle Implementierung der Kryptofunktionen. Unterstützt werden damit auch Verfahren auf Basis elliptischer Kurven oder die Hash-Algorithmen der SHA-2-Familie.

Vor allem die Diffie-Hellman-Verfahren auf Grundlage elliptischer Kurven werden dringend benötigt.

Zum einen wird der DH-Schlüsselaustausch für die „Perfect Forward Secrecy“ (PFS) benötigt, die eine nachträgliche Entschlüsselung aufgezeichneten HTTPS-Traffics mithilfe des privaten Schlüssels des Servers unmöglich macht [2]. Eine Anwendung, die vor allem gegen notorische Datensammler wie NSA und Co. nötig ist, da die ohne PFS alle in der Vergangenheit aufgezeichneten Verbindungen entschlüsseln können, sobald sie an den zugehörigen privaten Schlüssel des Servers gelangen.

Zum anderen sind Angriffe auf die herkömmlichen DH-Implementierungen auf Basis von Primzahlen möglich [3]. Vorerst sind nur die schwachen Exportversionen mit einer Primzahlenlänge von 512 Bit betroffen, aber auch 768- und 1 024-Bit-Primzahlen dürften nicht mehr all zu lange sicher sein.

Daher ist ein Wechsel auf die Diffie-Hellman-Verfahren auf Grundlage elliptischer Kurven angeraten, denen durch diese Angriffe keine Gefahr droht.

RC4 ist unsicher!

Und da ich gerade bei Kryptoalgorithmen und Gefahr bin: Nutzt irgendjemand von Ihnen noch RC4? Davor hat Microsoft schon im November 2013 gewarnt, und es gibt Hinweise darauf, dass die NSA SSL/TLS-Verschlüsselungen mit RC4 in Echtzeit brechen kann [4].

Zwei belgischen Forschern ist es nun gelungen, sechzehn Zeichen lange Session-Cookies innerhalb von rund 52 Stunden aus RC4-verschlüsseltem HTTPS-Traffic zu extrahieren.

Für den Angriff muss der Angreifer den Browser seines Opfers jedoch dazu bringen, eine große Anzahl HTTPS-Requests abzuschicken. Um ausreichend Traffic zur Analyse zu erhalten, müssen für die Kleinigkeit von 75 Stunden über 4 000 Requests pro Sekunde gesendet werden. Zumindest in der Theorie, im praktischen Versuch gelangten die Forscher nach den bereits erwähnten 52 Stunden ans Ziel. Zwar könnte ein MitM entsprechenden Code in den Browser des Opfers einschleusen, aber ob der lange genug läuft, wage ich doch zu bezweifeln.

Trotzdem ist nun erstmals praktisch erwiesen, dass ein Angriff möglich ist. Statt auf SSL/TLS ist der Angriff auch auf WPA-TKIP möglich, hier soll eine Stunde für einen erfolgreichen Angriff ausreichen. Was einen erfolgreichen Angriff sehr viel wahrscheinlicher erscheinen lässt.

Neues in WCF

Weiter geht es mit der Windows Communication Foundation (WCF). Auch dort gibt es Neues zur Kryptografie: Außer SSL 3.0 und TLS 1.0 wird nun auch TLS 1.1 und TLS 1.2 unterstützt. Eine Neuerung, die dringend nötig ist, denn sowohl SSL 3.0 als auch TLS 1.0 sind bereits negativ aufgefallen.

Auf SSL 3.0 ist der 2014 entwickelte so genannte Poodle-Angriff möglich. Eigentlich ist SSL 3.0 sowieso veraltet, ein als MitM agierender Angreifer kann jedoch den Fallback von TLS auf SSL 3.0 erzwingen. Danach kann er die Schwachstelle darin ausnutzen, um über einen Padding-Oracle-Angriff Teile der Kommunikation wie zum Beispiel Session-Cookies auszuspähen.

Der BEAST-Angriff auf SSL und TLS 1.0 stammt aus dem Jahr 2011, die zugrunde liegende Schwachstelle ist bereits seit 2001 bekannt. Über einen block-wise chosen-plaintext-Angriff wird durch das Einfügen präparierter Klartextblöcke auf den Klartext anderer Blöcke geschlossen. Konkret hat es der BEAST-Angriff – wie auch der Poodle-Angriff – dabei auf Session-Cookies abgesehen.

Ein kurzer Blick über den Tellerrand

C# ist ja eigentlich so eine Art (C++)++, daher sei ein Blick hinüber zum „Vorfahren“ gestattet: Für C++ enthält Visual Studio 2015 eine neue Mitigation, also eine Schutzmaßnahme, die bestimmte Angriffe zwar nicht vollständig verhindert, aber sehr viel komplizierter macht. Diese neue Mitigation ist die Control Flow Guard (CFG) und soll verhindern, dass ein Angreifer den vorgesehenen Ablauf des Programms durcheinander bringt und Code anspringt, der in der aktuellen Situation nicht angesprungen werden darf [23]. Der Visual C++ Compiler fügt in den Code zusätzliche Prüfungen ein, die eine Manipulation des Programmablaufs erkennen und das Programm stoppen, bevor der Angreifer Schaden anrichten kann.

Während die CFG in den Vorversionen von Visual Studio 2015 über den Schalter /d2guard4 aktiviert wurde, dient dafür nun der Schalter /guard:cf. Falls Sie auch in C++ entwickeln, sollten Sie vorhandene Projekte an diese Änderung anpassen.

Soviel zur Sicherheit, und wie sieht es mit Angriffen aus?

Es gibt ja nun nicht gerade überwältigend viele Neuerungen, wenn es um die Sicherheit geht. Und wie sieht es mit Angriffen auf C# 6.0 und .NET 4.6 aus? Sehr erfreulich, denn bisher wurden keine neuen Angriffe vorgestellt.

Dass die Cyberkriminellen noch nicht zur Tat geschritten sind, ist nicht weiter verwunderlich. Warum sollten die nach Schwachstellen in noch gar nicht fertigen Produkten suchen, die in der finalen Version vielleicht gar nicht mehr vorhanden sind? Oder diese sogar angreifen?

Damit warten sie im Allgemeinen, bis die Entwicklung abgeschlossen und die Produkte im produktiven Einsatz sind. Und dabei ist es total egal, ob das Produkt nun ein Betriebssystem wie Windows 10, ein Entwicklerwerkzeug wie C# oder Visual Studio oder eine Anwendung wie Microsoft Office ist. Erst die finale Version, die auf möglichst vielen Rechnern installiert ist, ist für Cyberkriminelle als Angriffsziel interessant.

Und was ist mit den Sicherheitsforschern?

Auch bei den Sicherheitsforschern ist es bisher ruhig geblieben. Entweder hat sich niemand für die Vorversionen von Windows 10 und allem drum herum interessiert, oder es wurden keine wirklich bemerkenswerten Angriffsmöglichkeiten gefunden.

Am nächsten dran am Thema sind Vorträge über das Umgehen von Mitigations. Zum Beispiel haben sich Daniel Lehmann und Ahmad-Reza Sadeghi auf der Black Hat USA 2014 mit Angriffen auf (oder besser: trotz) Schutzmaßnahmen für den Kontrollfluss beschäftigt. Und Byoungyoung Lee, Yeongjin Jang und Tielei Wang haben auf der gleichen Konferenz Möglichkeiten vorgestellt, die Adress Space Layout Randomization zu umgehen. Die erschwert das gezielte Anspringen vom Code im Speicher, indem der Code an zufällige Adressen geladen wird.

Die Mitigations betreffen Sie als C#-Entwickler aber nur am Rande. Die meisten Mitigations dienen dazu, Angriffe über Pufferüberlaufschwachstellen zu erschweren. Solange Sie nur Managed-Code verwenden, sind Pufferüberläufe in C# nahezu unmöglich. Nur wenn Sie gezielt als „unsafe“ markierten Code einsetzen und dann die Eingaben nicht korrekt prüfen, können Pufferüberlaufschwachstellen entstehen. Und zumindest Letzteres werden Sie natürlich niemals tun, nicht wahr? Ganz unabhängig davon, ob der Code nun safe oder unsafe ist.

Windows 10

Windows 10 und alles, was dazu gehört, wird aber schon in Kürze eine größere Rolle auf den Sicherheitskonferenzen spielen. Bereits auf der vom 1. bis 6. August stattfindenden Black Hat USA 2015 hat es einige Vorträge gegeben, die sich explizit mit Windows 10 beschäftigt haben.

Alex Ionescu hat sich mit der Sicherheit der neuen Systemarchitektur rund um Virtual Secure Machines (VSMs) und Secure Kernel Mode (SKM) auseinandergesetzt. Yunhai Zhang hat gezeigt, wie sich die oben erwähnte Control Flow Guard (CFG) umgehen lässt. Seth Moore und Baris Saydag haben Microsofts neueste Ansätze, das „Pass-the-Hash“-Problem in den Griff zu bekommen, untersucht. Und Mark Vincent Yason hat sich die Angriffsfläche der Edge HTML Rendering-Engine des Spartan-Browsers genauer angesehen.

Für die Black Hat wurden 32 0-Day-Schwachstellen angekündigt, also Schwachstellen, für die es bei ihrem Bekanntwerden noch keinen Patch gibt. Hoffen wir mal, dass darunter keine in Windows und Co. sind.

Fazit

Sicherheitsrelevante Änderungen gibt es in C# 6 nicht, aber die waren eigentlich auch nicht zu erwarten. Denn im Gegensatz zu C wurde C# ja von Anfang an auch im Hinblick auf die Sicherheit entwickelt, sodass viele Probleme gar nicht erst entstanden.

Im .NET Framework gibt es vor allem neue Kryptofunktionen, sodass Sie nun die Möglichkeit haben, die Daten und Kommunikation Ihrer Programme mit aktuellen Protokollen, Implementierungen, Verfahren und Schlüssellängen zu schützen. Aber die alten Implementierungen waren auch nicht wirklich unsicher, wenn man von veralteten Algorithmen wie RC4, veralteten Protokollen wie SSL 3.0 oder zu kurzen Primzahlen beim DH-Schlüsselaustausch absieht.

Und in der Hinsicht ist Kryptografie sowieso immer nur ein Zeitschloss. Irgendwann gibt es effektive Algorithmen und/oder Rechner, die einen Brute-Force-Angriff auf früher einmal als sicher eingestufte Schlüssellängen oder Algorithmen ermöglichen, oder in den Implementierungen oder Standards von Algorithmen oder Protokollen werden Schwachstellen entdeckt, die einen Angriff möglich machen.

Also: So lange Sie aktuelle Tools verwenden (egal ob Sprache, Entwicklungs- oder Laufzeitumgebung oder APIs), droht Ihren Programmen aus dieser Richtung keine Gefahr.

Links & Literatur

[1] Eilers, Carsten: „Microsoft Security Development Lifecycle“, in Windows Developer 4.2012

[2] Eilers, Carsten: „Heute aufgezeichnet – morgen entschlüsselt?“, in PHP Magazin 5.2014

[3] Eilers, Carsten: „Kurze Schlüssel, große Gefahr“, in PHP Magazin 5.2015

[4] Eilers, Carsten: „Kryptografie im NSA-Zeitalter“, in Entwickler Magazin 2.2014

Aufmacherbild: Security concept: Lock on digital screen von Shutterstock / Urheberrecht: Maksim Kabakou 

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

1 Kommentar auf "Wie sicher ist C#6?"

avatar
400
  Subscribe  
Benachrichtige mich zu:
Hans Sarin
Gast

So einen blöden Schmarrn hab ich noch nie gehört. Warum werden Sicherheit und die Implementierung von Properties miteinander in Verbindung gebracht? Clickbait!

X
- Gib Deinen Standort ein -
- or -