Sicherheit in Klassenbibliotheken

Als Entwickler von Klassenbibliotheken müssen Sie mit den Grundlagen der Codezugriffssicherheit vertraut sein, um sichere Klassenbibliotheken programmieren zu können. Beachten Sie beim Schreiben einer Klassenbibliothek zwei Sicherheitsregeln: Verwenden Sie Berechtigungen, um Objekte zu schützen, und schreiben Sie voll vertrauenswürdigen Code. In welchem Umfang diese Prinzipien zutreffen, hängt davon ab, welche Klasse Sie programmieren. Manche Klassen, z. B. die System.IO.FileStream-Klasse, stellen Objekte dar, die Schutz durch Berechtigungen erfordern. Die Implementierung dieser Klassen überprüft die Berechtigungen von Aufrufern und erlaubt nur autorisierten Aufrufern, die betreffenden Operationen auszuführen. Der System.Security-Namespace enthält Klassen, mit deren Hilfe Sie diese Überprüfungen in den Klassenbibliotheken, die Sie schreiben, ausführen können. Klassenbibliothekscode ist häufig voll vertrauenswürdiger oder zumindest hoch vertrauenswürdiger Code. Da Klassenbibliothekscode oft auf geschützte Ressourcen und nicht verwalteten Code zugreift, stellen Fehler im Code eine echte Gefahr für die Integrität des gesamten Sicherheitssystems dar. Um Sicherheitsprobleme zu minimieren, halten Sie sich beim Schreiben von Klassenbibliothekscode an die im Folgenden beschriebenen Richtlinien. Weitere Informationen hierzu finden Sie unter Erstellen von sicheren Klassenbibliotheken.

Schützen von Objekten durch Berechtigungen

Berechtigungen werden definiert, um bestimmte Ressourcen zu schützen. Eine Klassenbibliothek, die Operationen mit geschützten Ressourcen ausführt, muss diesen Schutz implementieren. Klassenbibliothekscode muss, bevor er auf eine Anforderung für eine geschützte Ressource (z. B. das Löschen einer Datei) reagiert, zuerst überprüfen, ob der Aufrufer (bzw. in der Regel alle Aufrufer, durch einen Stackwalk) die erforderlichen Berechtigungen für den Ressourcenvorgang hat. Ist dies der Fall, sollte die Aktion ausgeführt werden können. Andernfalls sollte die Aktion nicht ausgeführt werden können, und eine Sicherheitsausnahme sollte ausgelöst werden. Dieser Schutz wird im Code typischerweise entweder mit einer deklarativen oder einer imperativen Überprüfung der entsprechenden Berechtigungen implementiert.

Es ist wichtig, dass Ressourcen durch Klassen nicht nur vor direktem Zugriff, sondern auch vor jeglicher Art von Offenlegung geschützt werden. So muss beispielsweise ein zwischengespeichertes Dateiobjekt Dateileseberechtigungen überprüfen, auch wenn die eigentlichen Daten aus einem Zwischenspeicherbereich abgerufen werden und keine tatsächliche Dateioperation erfolgt. Grund hierfür ist, dass die Übergabe der Daten an den Aufrufer den gleichen Effekt hat, wie wenn der Aufrufer eine tatsächliche Leseoperation ausgeführt hätte.

Voll vertrauenswürdiger Klassenbibliothekscode

Viele Klassenbibliotheken werden als voll vertrauenswürdiger Code implementiert, der plattformspezifische Funktionen als verwaltete Objekte einkapselt, z. B. als COM- oder System-APIs. Voll vertrauenswürdiger Code kann eine Schwachstelle für das gesamte System darstellen. Wenn Klassenbibliotheken jedoch im Hinblick auf die Sicherheit korrekt programmiert werden, kann der Großteil des verwalteten Codes durch Anwenden einer hohen Sicherheitshürde auf einen relativ kleinen Satz Klassenbibliotheken und die zentrale Runtimesicherheit die Sicherheitsvorteile dieser Kernklassenbibliotheken übernehmen.

In einem üblichen Sicherheitsszenario für Klassenbibliotheken legt eine voll vertrauenswürdige Klasse eine Ressource offen, die durch eine Berechtigung geschützt wird. Auf die Ressource wird durch eine API in systemeigenem Code zugegriffen. Ein typisches Beispiel für diese Art von Ressource ist eine Datei. Die File-Klasse verwendet eine systemeigene API, um Dateioperationen auszuführen, z. B. einen Löschvorgang. Die folgenden Schritte werden unternommen, um die Ressource zu schützen.

  1. Ein Aufrufer fordert die Löschung der Datei C:\test.txt an, indem er die File.Delete-Methode aufruft.
  2. Die Delete-Methode erstellt ein Berechtigungsobjekt, das die delete c:\test.txt-Berechtigung darstellt.
  3. Der Code der File-Klasse überprüft bei allen Aufrufern im Stack, ob sie die erforderliche Berechtigung haben. Ist dies nicht der Fall, wird eine Sicherheitsausnahme ausgelöst.
  4. Die File-Klasse bestätigt FullTrust, um systemeigenen Code aufzurufen, da die betreffenden Aufrufer möglicherweise diese Berechtigung nicht haben.
  5. Die File-Klasse verwendet eine systemeigene API, um Dateilöschung auszuführen.
  6. Die Rückgabe von der File-Klasse an den Aufrufer erfolgt, und die Anforderung für die Dateilöschung wird erfolgreich ausgeführt.

Vorsichtsmaßnahmen für hoch vertrauenswürdigen Code

Dem Code in einer vertrauenswürdigen Klassenbibliothek werden Berechtigungen gewährt, die dem Großteil des Anwendungscodes nicht zur Verfügung stehen. Außerdem kann eine Assembly Klassen enthalten, die keine speziellen Berechtigungen benötigen, diese aber erhalten, da die Assembly andere Klassen enthält, für die diese Berechtigungen erforderlich sind. Diese Situationen können eine Schwachstelle für die Systemsicherheit darstellen. Gehen Sie deshalb sehr sorgfältig vor, wenn Sie hoch oder voll vertrauenswürdigen Code schreiben.

Formulieren Sie vertrauenswürdigen Code so, dass er von beliebigem halb vertrauenswürdigen Code im System aufgerufen werden kann, ohne dass eine Sicherheitslücke entsteht. Ressourcen werden in der Regel mit Hilfe eines Stackwalks durch alle Aufrufer geschützt. Wenn ein Aufrufer nicht die erforderlichen Berechtigungen besitzt, wird der Zugriffsversuch zurückgewiesen. Immer, wenn jedoch vertrauenswürdiger Code eine Berechtigung bestätigt, ist der Code für die Überprüfung der erforderlichen Berechtigungen verantwortlich. In der Regel sollte auf eine Berechtigungsprüfung für einen Aufrufer eine Bestätigung folgen, wie weiter oben beschrieben. Darüber hinaus sollte die Anzahl der Bestätigungen für höhere Berechtigungen minimiert werden, um das Risiko einer unbeabsichtigten Offenlegung zu verringern.

Voll vertrauenswürdigem Code werden alle anderen Berechtigungen implizit gewährt. Außerdem ist es zulässig, dass dieser Code gegen Regeln für die Typsicherheit und die Objektverwendung verstößt. Unabhängig vom Schutz von Ressourcen kann jeder Aspekt der programmgesteuerten Schnittstelle, der die Typsicherheit unterläuft oder Zugriff auf Daten ermöglicht, die dem Aufrufer normalerweise nicht zur Verfügung stehen, zu einem Sicherheitsproblem führen.

Leistung

Bei der Sicherheitsüberprüfung wird auch der Stack auf die Berechtigungen aller Aufrufer untersucht. Je nach Stacktiefe können diese Operationen die Leistung stark beeinträchtigen. Wenn eine Operation tatsächlich aus einer Reihe von Aktionen einer untergeordneten Ebene besteht, die Sicherheitsüberprüfungen erfordern, kann es zu einer deutlichen Leistungssteigerung beitragen, wenn die Berechtigungen der Aufrufer einmal überprüft werden und die erforderliche Berechtigung dann bestätigt wird, bevor die Aktionen ausgeführt werden. Durch die Bestätigung wird verhindert, dass der Stackwalk im Stack nach oben weitergegeben wird, so dass die Überprüfung an dieser Stelle gestoppt und erfolgreich abgeschlossen wird. Diese Technik führt in der Regel zu einer verbesserten Leistung, wenn drei oder mehr Berechtigungsprüfungen auf einmal abgedeckt werden können.

Zusammenfassung: Sicherheitsaspekte bei Klassenbibliotheken

  • Für jede Klassenbibliothek, die geschützte Ressourcen verwendet, muss sichergestellt werden, dass die Verwendung dieser Ressourcen nur im Rahmen der Berechtigungen des Aufrufers erfolgt.
  • Die Bestätigung von Berechtigungen sollte nur wenn nötig erfolgen, und zwar nach der Überprüfung der erforderlichen Berechtigungen.
  • Um eine Leistungssteigerung zu erzielen, aggregieren Sie Operationen, die Sicherheitsprüfungen beinhalten, und verwenden Sie u. U. eine Bestätigung, um Stackwalks auf ein Mindestmaß zu reduzieren, ohne die Sicherheit zu beeinträchtigen.
  • Machen Sie sich bewusst, auf welche Weise ein halb vertrauenswürdiger Aufrufer eine Klasse mutwillig verwenden könnte, um Sicherheitsfunktionen zu umgehen.
  • Gehen Sie nicht von der Annahme aus, dass Code nur durch Aufrufer mit bestimmten Berechtigungen aufgerufen wird.
  • Definieren Sie keine nicht-typsicheren Schnittstellen, mit Hilfe derer die Sicherheit an anderen Stellen umgangen werden könnte.
  • Legen Sie keine Funktionen in einer Klasse offen, durch die ein halb vertrauenswürdiger Aufrufer die höhere Vertrauenswürdigkeit der Klasse ausnutzen könnte.

Siehe auch

Entwurfsrichtlinien für die Entwicklung von Klassenbibliotheken | Erstellen von sicheren Klassenbibliotheken | Codezugriffssicherheit | Sicherheits- und kulturbezogene Zeichenfolgenoperationen