Sicherheitsverbesserungen in .NET 2.0

Veröffentlicht: 09. Mai 2006

Von Keith Brown

Version 2.0 des Microsoft ® .NET Frameworks ist veröffentlicht. Als ich ein Jahr zuvor erstmalig mit der Beta 2 in Berührung kam, habe ich ein kleines Programm geschrieben, das alle öffentlichen Member sämtlicher öffentlicher Typen im gesamten Framework abbildet. Ich führte dieses Programm in Version 1.1 und in der Beta der Version 2.0 aus. Ich setzte dann WINDIFF.EXE ein, um die beiden Textdateien zu vergleichen. Ich ging die so gefundenen Änderungen durch, machte mir Notizen und achtete besonders auf sicherheitsbezogene Aspekte.

Die Sicherheitsunterstützung hat in Version 2.0 viel Aufmerksamkeit erhalten. Dieser Artikel führt Sie durch die vorhandenen Funktionen. Ich werde nicht alles behandeln können, Sie werden jedoch einen Überblick über die Erweiterungen erhalten: Ich werde einen Namespace nach dem anderen erläutern.

Auf dieser Seite

System.Security
System.Security.Principal
System.Security.AccessControl
System.Net.Security
System.Runtime.Remoting
System.Security.Cryptography
System.Security.Cryptography.X509Certificates und PKCS
System.Security.Cryptography.Xml
System.Diagnostics
System.DirectoryServices
System.DirectoryServices.ActiveDirectory
System.Web
Änderungen der Codezugriffssicherheit
Zusammenfassung
Der Autor

System.Security

Verwaltete Zeichenfolgen sind schlechte Speichermedien für vertrauliche Daten. Es gibt keine wirkliche Möglichkeit, sie zu löschen. Die Garbage Collection kann nicht garantieren, dass gesammelter Speicher auch überschrieben wird. In vielen Fällen verbleiben nicht mehr verwendete Zeichenfolgen daher noch einige Zeit im verwalteten Heap, bevor sie durch eine Heapkomprimierung überschrieben werden. Außerdem werden diese Zeichenfolgen möglicherweise vom Garbage Collector innerhalb des verwalteten Heaps verschoben. In Verbindung mit der Tatsache, dass alter Speicher nicht unwiderruflich gelöscht wird, erhalten Sie im Adressraum möglicherweise viele Instanzen der Zeichenfolge, die Sie geheim zu halten versuchen. Eine neue Klasse, SecureString, wurde eingeführt, um diese Probleme zu verringern.

Diese Klasse speichert Daten mit dem geschützten Speichermodell der DPAPI (Data Protection API). Anders ausgedrückt sind Daten immer verschlüsselt, wenn sie in einem SecureString gespeichert sind. Der Verschlüsselungsschlüssel wird von LSASS.EXE (Local Security Authority Subsystem) verwaltet. Mit der DPAPI können die Daten per prozessübergreifender Kommunikation entschlüsselt werden.

Damit diese Klasse wirksam sein kann, muss jede .NET Framework-Methode, die vertrauliche Daten liest (etwa ein Kennwort aus der Konsole oder eine Verbindungszeichenfolge aus web.config), diese Daten direkt in einer SecureString-Klasse kapseln und an Sie zurückgeben. Sie können eine gewöhnliche Zeichenfolge nicht einfach in einer SecureString-Klasse verpacken und erwarten, dass sie dadurch sicherer wird: Die vertraulichen Daten dürfen zu keiner Zeit in eine gewöhnliche verwaltete Zeichenfolge gelangen.

Die gleiche Regel gilt für das Zurückgeben von vertraulichen Daten an .NET Framework. So hat bspw. die neue Password-Eigenschaft in ProcessStartInfo (ich werde dies an späterer Stelle erläutern) den Typ SecureString. Intern verwendet .NET Framework die Marshal-Klasse, um bei Bedarf den eigentlichen Inhalt der vertraulichen Daten abzurufen. Hierzu werden neue Funktionen verwendet, bspw. Marshal.SecureStringToBSTR. Da die Marshal-Klasse in nicht verwaltetem Speicher arbeitet, kann dieser Speicher wirklich unwiderruflich gelöscht werden, wenn er vom Framework nicht mehr verwendet wird. Sie können nicht ToString verwenden, um vertrauliche Daten von SecureString abzurufen. Denken Sie immer daran, dass vertrauliche Daten nie in ein gewöhnliches Zeichenfolgenobjekt gelangen dürfen.

Ich kann allerdings keine Möglichkeit erkennen, vertrauliche Daten aus der Windows-Auslagerungsdatei herauszuhalten. Wenn die vertraulichen Daten in den systemeigenen Speicher zurückgeschrieben werden, sehe ich keine Möglichkeit sicherzustellen, dass die Seite, auf die die Daten zurückgeschrieben werden, mit VirtualLock gesperrt wird.

Weiterhin kann ich keine umfassende Integration von SecureString im Framework ausmachen, obwohl die RTM-Anteile diesbezüglich etwas weiter gehen als die frühe Beta. Sie werden wahrscheinlich in der neuen Überladung für System.Diagnostics.Process.Start auf diese Klasse treffen, die die Angabe von Benutzernamen und Kennwort erlaubt. Hier wird die zugrunde liegende Win32® CreateProcessWithLogonW-Funktion verwendet, um einen Prozess zu erstellen, der in einer neuen Anmeldesitzung mit den von Ihnen angegebenen Benutzeranmeldeinformationen ausgeführt wird. Sie können das Kennwort als SecureString angeben. Im System.Security.Cryptography-Namespace wird SecureString in drei Klassen verwendet: CspParameters und zwei Zertifikatsklassen, X509Certificate und X509Certificate2. SecureString wird auch in einer der MSBuild-Aufgaben verwendet. Was ich jedoch wirklich gerne hätte, ist folgender Konstruktor:

public SqlConnection(SecureString connStr);

Ich hätte auch gerne eine verwaltete Klasse, die als Wrapper für Win32-Funktionen wie CredUIPromptForCredentials dient, damit der Benutzer nach einem Kennwort gefragt und ein SecureString als Ergebnis zurückgegeben werden kann. Eine solche Integration wird der Schlüssel zum Erfolg dieses Features sein.

Neben SecureString hat eine weitere Klasse in diesem Namespace meine Aufmerksamkeit erregt: SecurityContext. Was für eine leistungsstarke Klasse! Mit ihr können Sie den Sicherheitskontext eines Threads erfassen und in einem anderen Thread wiederherstellen. Dies schließt die CAS-(Code Access Security-)Threadmarkierungen, wie Assert und PermitOnly, und auch den Identitätswechseltoken für den nicht verwalteten Thread ein.

In dieser Klasse gibt es einige ungewöhnliche Funktionen, z. B. SuppressFlow. Diese Funktion steuert, ob CAS-Markierungen von einem Thread in einen anderen übertragen werden (in der Regel ist dies der Fall). Dann gab es da noch die Überraschung: SuppressFlowWindowsIdentity. Jeder, der sich länger mit Sicherheitsprogrammierung in Windows® beschäftigt hat, weiß, dass beim Erstellen eines neuen Threads oder beim Durchführen eines asynchronen Aufrufs über eine Delegierung der Identitätswechseltoken bislang nicht in den neuen Thread übertragen wurde. Dieser kleine Sicherheitsfehler ist im Lauf der Zeit mehr als ein paar Entwicklern unterlaufen. Nun, wenn SecurityContext eine Funktion zum Unterdrücken der threadübergreifenden Übertragung einer WindowsIdentity bietet, muss dies bedeuten, dass in .NET Framework Identitätswechseltoken jetzt automatisch übertragen werden.

Zum Testen habe ich etwas Code geschrieben, der LogonUser aufruft und die Identität des sich ergebenden Tokens annimmt. Danach wendete ich eine raffinierte neue Überladung der GetCurrent-Methode auf WindowsIdentity an, um festzustellen, ob die Identität angenommen wurde oder nicht (hierzu später mehr). Diese Funktion wurde an vier verschiedenen Stellen aufgerufen: im Hauptthread, einem neuen, mit Thread.Start erstellten Thread, einem über eine asynchrone Delegierung erstelltem Workerthread und einem Thread, der mit unserem guten alten Freund aus Win32 erstellt wurde, CreateThread. Ich habe sogar QueueUserWorkItem getestet, deren Verhalten hinsichtlich der Übertragung des Sicherheitskontexts (insbesondere CAS-Markierungen) früher etwas anders war. Hier ist die Ausgabe:

Main thread
Thread 2488 is impersonating V-CAMP-XP\alice
Testing Thread.Start
Thread 2508 is impersonating V-CAMP-XP\alice
Testing QueueUserWorkItem
Thread 2504 is impersonating V-CAMP-XP\alice
Testing Delegate.BeginInvoke
Thread 2516 is impersonating V-CAMP-XP\alice
Testing Native CreateThread
Thread 2520 is not impersonating!

Toll! Die Laufzeit überträgt jetzt tatsächlich Identitätswechseltoken automatisch von Thread zu Thread. Wenn Sie dieses Verhalten ändern möchten, können Sie die SecurityContext-Klasse verwenden (obwohl ich dies nicht empfehle).

Der von der nicht verwalteten API CreateThread erstellte Thread wird nicht abgedeckt. Dies ist jedoch zu erwarten, da die Laufzeitumgebung hierfür verantwortlich ist, nicht das Betriebssystem. Aufrufe an InProc-COM-Komponenten, die Threadänderungen aufgrund von Threadmodellkonflikten generieren, werden daher weiterhin den Identitätswechseltoken verwerfen. Das Identitätsflussproblem zwischen Threads wurde jedoch für eine große Anzahl von Anwendungen gelöst. Dies sind gute Neuigkeiten, da die Ergebnisse so weniger überraschend ausfallen. Dies ist eine wichtige und raffinierte Änderung. Seien Sie also vorbereitet, wenn Sie in Ihrer Anwendung Identitätswechsel oder asynchrone Funktionen verwenden.

System.Security.Principal

Die neue Klasse, die eine SID (Security Identifier) modelliert, wirkt nicht sehr wichtig, sie legt jedoch den Grundstein für eine umfassende Unterstützung der Windows-Sicherheitsprogrammierungsschnittstelle. In Zukunft werde ich viel weniger Zeit mit dem Schreiben von verwaltetem C++-Code zum Schließen der Lücken verbringen, und das macht mich glücklich. Drei Klassen ermöglichen dies. Die ersten beiden sind konkrete Klassen, mit denen auf ein Sicherheitskonto verwiesen werden kann (Benutzer, Gruppe oder Computer): SecurityIdentifier, die die vom Computer lesbare SID darstellt, und NTAccount, für die vom Benutzer lesbare Zeichenfolge. Die dritte, eine abstrakte Klasse mit dem Namen IdentityReference, verbindet diese Klassen.

Eine Methode, die normalerweise eine SID, eine Sammlung von SIDs oder eine Sammlung von Datenstrukturen zurückgibt, die SIDs enthalten, verwendet die abstrakte Klasse in ihrer Signatur. Die Methode benötigt ein zusätzliches Typargument, damit Sie auswählen können, ob die Methode SIDs oder Namen zurückgeben soll. Sie können dann eine geeignete Typumwandlung sicher durchführen. Das folgende Beispiel zeigt den Kontonamen des Benutzers an, der eine Datei besitzt:

void printTheOwnerOfThisFile(string path) {
    FileSecurity s = File.GetAccessControl(path);
    NTAccount user = (NTAccount)s.GetOwner(typeof(NTAccount));
    Console.WriteLine(user);
}
...
printTheOwnerOfThisFile(@"c:\autoexec.bat");

Wenn ich diesen Code auf meinem System ausführe, wird die folgende Zeichenfolge angezeigt:

BUILTIN\Administrators

Eine vollständige Liste bekannter SIDs ist in der neuen Enumeration WellKnownSidType enthalten. Dies macht das Erstellen von SIDs für bekannte Konten trivial, ohne Zeichenfolgen wie "Administratoren" hart codieren zu müssen, deren Schreibweisen sich in Deutschland und den Vereinigten Staaten unterscheiden.

Die WindowsIdentity-Klasse hat ebenfalls etwas Aufmerksamkeit erhalten. Wie bereits erwähnt, ist eine meiner Lieblingserweiterungen eine Überladung von GetCurrent, mit der Sie während des Identitätswechsels zwischen dem Thread- und Prozesssicherheitskontext unterscheiden können:

bool ifImpersonating = true;
WindowsIdentity threadIdentity =
    WindowsIdentity.GetCurrent(ifImpersonating);
if (null == threadIdentity) Console.WriteLine("Not impersonating");
else Console.WriteLine("Impersonating {0}", threadIdentity.Name);

System.Security.AccessControl

Dieses Thema ist umfangreich. Im Framework werden jetzt Windows-Sicherheitsdeskriptoren modelliert. Dies ermöglicht ein programmgesteuertes Lesen und Ändern von Zugriffssteuerungslisten (ACLs), Übernehmen des Besitzes von Objekten, Konvertieren zwischen SDDL-(Security Descriptor Description Language-)Zeichenfolgen und binären Sicherheitsdeskriptoren und mehr. Ich habe die Entwicklung dieses Namespaces seit der Alpha-Vorabversion verfolgt, und ich muss sagen, dass die nach der Alpha in den Namespace investierte Arbeit diesen zu einer wirklich leistungsstarken und leicht zu verwendenden Erweiterung gemacht hat.

Ein einfaches Beispiel für dieses neue Feature ist das bereits erwähnte Ausgeben des Besitzers einer Datei. Beachten Sie, wie auf den Sicherheitsdeskriptor der Datei mit der System.IO.File-Klasse zugegriffen werden konnte. Sichere Objekte im Framework verfügen über zwei neue Methoden: GetAccessControl und SetAccessControl. Klassen wie AutoResetEvent, Mutex und die neue Semaphore-Klasse stellen drei solcher Objekte dar, genau wie die offensichtlicheren Klassen File und Directory.

Es gibt keine direkte Möglichkeit, die DACL (Discretionary Access Control List) eines Dienstes zu ändern. Zurzeit ist einfach keine integrierte, verwaltete Darstellung von Dienstobjekten vorhanden. Nachdem ich jedoch die Funktionsweise der Zugriffssteuerungsinfrastruktur verstanden hatte, brauchte ich etwa 15 Minuten, um eine eigene Unterstützung für Dienstsicherheit zu erstellen. Der System.Security.AccessControl-Namespace wurde von Beginn an unter Berücksichtung der Erweiterbarkeit entwickelt. Respekt!

Jeder, der schon einmal ACLs programmiert hat, wird die Einfachheit des Codes zu schätzen wissen (siehe Abbildung 1). Weitere Informationen zum System.Security.AccessControlNamespace finden Sie in Mark Pustilniks Artikel in der November 2004-Ausgabe des MSDN®Magazine, verfügbar unter Safety in Windows: Manage Access to Windows Objects with ACLs and the .NET Framework (in englischer Sprache).

System.Net.Security

Eines meiner bevorzugten Diskussionsthemen sind Authentifizierungsprotokolle, mit diesen zu programmieren war bislang jedoch eher kompliziert. Das Hinzufügen von Kerberos zu einer Anwendung beinhaltete das Aufrufen einiger Low-Level-Funktionen in der Security Support Provider-Schnittstelle (SSPI – Security Support Provider Interface). Das Hinzufügen von SSL-(Secure Sockets Layer-)Unterstützung war sogar noch schwieriger.

Zum Glück gibt es jetzt verwaltete Wrapper für die SSPI, mit denen Sie client- und serverseitig sichere Kanäle mit Kerberos oder SSL implementieren können. Die Kerberos-Unterstützung wird durch die NegotiateStream-Klasse ermöglicht, die technisch zwischen Kerberos und einem älteren Challenge-Response-Protokoll namens NTLM vermittelt. Der clientseitige Handshake kann entweder synchron oder asynchron erfolgen. Ein Beispiel für einen synchron eingerichteten Client:

NegotiateStream secureChannel = new NegotiateStream(networkStream);
secureChannel.AuthenticateAsClient(
    CredentialCache.DefaultNetworkCredentials,
    "SSPISample/TargetMachine:4242",
    ProtectionLevel.EncryptAndSign,
    TokenImpersonationLevel.Impersonation);

Nachdem Sie dies durchgeführt haben, können Sie secureChannel genau wie einen normalen NetworkStream verwenden. Daten, die durch secureChannel übertragen werden, sind jedoch mit einem Nachrichtenauthentifizierungscode (MAC – Message Authentication Code) integritätsgeschützt und verschlüsselt. Auf Serverseite muss ebenfalls eine Instanz von NegotiateStream vorhanden sein, damit die eingehenden Nachrichten entschlüsselt werden können, und der Server mit der RemoteIdentity-Eigenschaft eine WindowsIdentity abrufen kann, die den Client darstellt. Der Server kann nun die Identität von rollenbasierten Zugriffsprüfungen annehmen oder diese durchführen.

Die SslStream-Klasse sieht ähnlich aus, verwendet jedoch bei der Authentifizierung X.509-Zertifikate statt Kerberos-Tickets. Sie ermöglicht dem Client eine Prüfung hinsichtlich Serverzertifikatssperrung und das Ausstellen eines Clientzertifikats zur gegenseitigen Authentifizierung. Genauso können Sie nach Abschluss des Authentifizierungshandshakes Daten per Push- oder Pullvorgang durch die Pipe übertragen und sicher sein, dass diese integritätsgeschützt und verschlüsselt sind.

System.Runtime.Remoting

Eine weitere interessante Entwicklung ist das neue Unterstützen von Sicherheit durch den TCP-Channel. Dies wird mit der bereits erwähnten NegotiateStream-Klasse in den Channel integriert, und kann durch Angeben einiger neuer Attribute in den Remotekonfigurationsdateien des Clients und des Servers aktiviert werden. In diesem Artikel steht nicht genügend Platz für eine ausführliche Behandlung dieses Themas zur Verfügung, es gibt jedoch ein Kapitel in meinem Buch, das sich damit befasst. Sie finden dieses online unter The .NET Developer's Guide to Windows Security (in englischer Sprache).

System.Security.Cryptography

Die DPAPI ist jetzt ein wesentlicher Bestandteil des .NET Frameworks. Zwei .NET-Klassen, ProtectedData und ProtectedMemory, machen ihre Verwendung sehr einfach. Sie müssen einen Verweis auf System.Security.dll hinzufügen, um diese Klassen zu verwenden:

private static byte[] Decrypt(byte[] ciphertext) {
    byte[] applicationEntropy = Encoding.ASCII.GetBytes("AcmeWidgets");
    return ProtectedData.Unprotect(ciphertext, applicationEntropy,
        DataProtectionScope.LocalMachine);
}

Benutzern, die mit .NET Framework Verschlüsselungssysteme erstellen, wird eine vollständig neue Klassenfamilie geboten, die sich aus der neuen abstrakten Klasse HMAC (Keyed-Hash Message Authentication Code) ableitet. Alle umfangreichen SHA-(Secure Hash Algorithm-)Varianten werden abgedeckt. Ein Beispiel:

byte[] CalcMAC(byte[] key, byte[] msg) {
    return new HMACSHA256(key).ComputeHash(msg);
}

Wenn Sie kennwortbasierte Kryptografie durchführen und Schlüsselmaterial aus Kennwörtern oder Passphrasen generieren, können Sie jetzt den Algorithmus PKCS #5 nach Industriestandard verwenden, um einen Bytedatenstrom aus einem Kennwort zu erstellen (der Standard wird in RFC 2898 dokumentiert, in englischer Sprache verfügbar unter Password-Based Cryptography Specification Version 2.0.) Die neue Rfc2898DeriveBytes-Klasse macht das Absichern von Kennwörtern einfach, wie ich in meinem Artikel im Oktober 2004 beschrieben habe (siehe Security Briefs: Password Minder Internals, in englischer Sprache). Intern wird hier die PBKDF2-Funktion mit HMAC-SHA-1 verwendet:

void CreateNewUserAccount(string name, string pwd) {
    Rfc2898DeriveBytes db = new Rfc2898DeriveBytes(pwd, 32, 1000);
    byte[] hash = db.GetBytes(32);
    addUserAccountToDatabase(name, db.Salt, hash);
}

System.Security.Cryptography.X509Certificates und PKCS

Nie wieder CAPICOM! Diese neuen Namespaces bieten Ihnen verwaltete Wrapper für das kryptografische API (CAPI), mit denen Sie Zertifikate verwalten und mit CMS/PKCS #7 verpackte oder signierte Nachrichten direkt aus jeder verwalteten Sprache erstellen können.

Der Benutzer soll zum Auswählen eines Zertifikats aus seinem persönlichen Speicher aufgefordert werden? Dies ist jetzt leicht durchzuführen:

X509Store store = new X509Store("My", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certs =
    X509Certificate2UI.SelectFromCollection(store.Certificates, 
        "MyTitle", "MyMessage", X509SelectionFlag.SingleSelection);
if (1 == certs.Count) {
    Console.WriteLine("You selected \"{0}\"",
        certs[0].SubjectName.Name);
}
else Console.WriteLine("You canceled my dialog!");

Abbildung 2 zeigt das sich ergebende Dialogfeld.

Auswählen eines Zertifikats
Abbildung 2   Auswählen eines Zertifikats

System.Security.Cryptography.Xml

Dieser Namespace wurde mit der Unterstützung von XML Encryption erweitert. Weitere Informationen zur Verwendung von XML Signature und XML Encryption zum sicheren Austausch von Daten finden Sie im Artikel von Mike Downen und Shawn Farkas in der November 2004-Ausgabe des MSDN Magazine unter Trustworthy Code: Exchange Data More Securely with XML Signatures and Encryption (in englischer Sprache).

System.Diagnostics

Neben einer ganzen Reihe neuer Ablaufverfolgungs- und Debugfeatures, verbesserter Unterstützung des Ereignisprotokolls und sogar einer Stopwatch-Klasse ist in dieser Prozessklasse ein echtes Juwel versteckt: Die Möglichkeit, CreateProcessWithLogonW ohne die explizite Verwendung von P/Invoke aufzurufen. Dies ist das in Windows enthaltene Feature Ausführen als, das Entwickler zum Ausführen von Programmen zu Testzwecken mit unterschiedlichen Anmeldeinformationen verwenden. Dieses Feature kann nun einfach programmgesteuert in verwaltetem Code verwendet werden:

void RunNotepadAsThisUser(string authority,
    string principal, SecureString password) 
{
    Process.Start(@"c:\windows\notepad.exe",
        principal, password, authority).Dispose();
}

Beachten Sie die Verwendung von SecureString. Dies ist die einzige Schwierigkeit, denn woher erhalten Sie diese Zeichenfolge? Ein Ansatz ist die Verwendung eines der Anmeldeinformations-APIs in Win32, z. B. CredUIPromptForCredentials, um den Benutzer nach einem Kennwort zu fragen. Anschließend wird die nicht verwaltete Zeichenfolge in eine SecureString-Instanz verpackt, die dann an die Process.Start-Methode übergeben wird. Danach wird der Puffer, in dem das Kennwort gespeichert war, sorgfältig und unwiderruflich gelöscht.

System.DirectoryServices

Die wichtigste Änderung in diesem Namespace scheint die hinzugefügte Unterstützung für die Ansicht virtueller Listen (VLV – Virtual List View) zu sein. Dieses Windows Server™ 2003-Feature ermöglicht sehr umfangreiche Suchen und effizientes Navigieren in den Ergebnissen. Das vollständige Resultset muss nicht in einem Schritt abgerufen werden. Mit der VLV können Sie einen gewünschten Ergebnisbereich festlegen und in diesem anschließend navigieren. In dem folgenden Beispiel wird die Gesamtstruktur nach allen Benutzern durchsucht. Es werden jedoch nur die ersten 25 Datensätze zurückgegeben:

DirectorySearcher search = new DirectorySearcher(
    "(&(objectClass=user)" + "(objectCategory=person))");
search.VirtualListView = new DirectoryVirtualListView(25);
foreach (SearchResult result in search.FindAll()) {
    Console.WriteLine(result.Path);
}

Nachdem Sie eine VLV erstellt und diese an eine Suche angehängt haben, können Sie den Bereich der angezeigten Ergebnisse durch Festlegen von Eigenschaften wie Offset (Index im Ergebnissatz nach Datensatznummer), TargetPercentage (Index im Ergebnissatz nach einem Prozentsatz der Anzahl der Datensätze) oder Target (Index im Ergebnissatz nach einer Zeichenfolge, mit der das gewünschte Ergebnis beginnen soll) steuern.

System.DirectoryServices.ActiveDirectory

Es handelt sich hier um einen neuen Namespace, der das Anzeigen and Ändern der physischen und logischen Konfiguration von Active Directory® vereinfacht. Im Folgenden werden einige Klassennamen aufgeführt, um Ihnen zu veranschaulichen, was entworfen wurde: Forest, Site, Domain, DomainController, GlobalCatalog und viele mehr. Gleichzeitig wird ein Satz von Klassen bereitgestellt, mit denen das Active Directory-Schema gelesen und geändert werden kann. Ich könnte einen eigenen Artikel zu diesem Namespace schreiben. Es gibt hier viele nützliche Dinge, die Sie sich ansehen sollten. Eine ausführliche Diskussion finden Sie in The .NET Developers Guide to Directory Services Programming von Joe Kaplan und Ryan Dunn (Addison-Wesley Professional, Mai 2006).

System.Web

Im Juni 2004 schrieb ich einen Artikel über die neuen Sicherheitsfeatures in ASP.NET 2.0 (siehe Security: Security Headaches? Take ASP.NET 2.0!, in englischer Sprache). Es gibt jedoch ein Thema, das ich nicht behandelt habe: das Verschlüsseln von Konfigurationsdateien. Wäre es nicht schön, in .NET Framework einen ganzen Abschnitt der Konfigurationsdatei mit DPAPI verschlüsseln zu können, z. B. den AppSettings-Abschnitt? Mit der folgenden Befehlszeile können Sie genau dies durchführen:

aspnet_regiis -prov DataProtectionConfigurationProvider
  -pef appSettings c:\web

Aus einer web.config-Datei

<configuration>
  <appSettings>
    <add key='MySecret' value='Attack at dawn'/>
  </appSettings>
</configuration>

wird Folgendes (der verschlüsselte Text wurde zwecks Lesbarkeit gekürzt):

<configuration>
  <appSettings configProtectionProvider="DataProtectionConfigurationProvider">
    <EncryptedData>
      <CipherData>
        <CipherValue>AQAAANCMnd...</CipherValue>
      </CipherData>
    </EncryptedData>
  </appSettings>
</configuration>

Wie greifen Sie nun auf die "geheimen" Daten zu? Das ist der interessante Teil. Der Zugriff auf die Daten funktioniert wie bisher, die Entschlüsselung findet im Hintergrund statt:

Console.WriteLine(ConfigurationSettings.AppSettings["MySecret"]);

Sie können auch einen RSA-Anbieter verwenden, der einen CAPI-Schlüsselcontainer zum Speichern des Verschlüsselungsschlüssels verwendet. Sie können diese Klasse beispielsweise verwenden, wenn eine einzelne CONFIG-Datei auf vielen verschiedenen Computern einer Webfarm bereitgestellt werden soll. Mit CAPI kann der Verschlüsselungsschlüssel für die gesamte Farm synchronisiert werden, wohingegen DPAPI eine computerspezifische Verschlüsselungsmethode ist. Das Patterns & Practices-Team hat eine Reihe von Dokumenten zusammengestellt, in denen die Verwendung dieses und anderer Sicherheitsfeatures in Version 2.0 erläutert wird (in englischer Sprache verfügbar unter Security Guidance for Applications Index).

Änderungen der Codezugriffssicherheit

In Version 2.0 von .NET Framework wurde einiges zur CAS-Infrastruktur hinzugefügt. Ein neues Konzept mit transparenten und nicht transparenten Assemblys kann das Durchführen von Sicherheitsprüfungen in Szenarios mit teilweiser Vertrauenswürdigkeit vereinfachen. Shawn Farkas hat eine hervorragende Beschreibung dieser Ideen und ihrer Verwendung in seinem Weblog veröffentlicht: Marking Your Code Transparent (in englischer Sprache).

Eine neue Beweisklasse gibt aus, ob eine Assembly aus dem globalen Assemblycache (GAC) geladen wurde. Beachten Sie, dass hinsichtlich des GAC eine wesentliche Änderung an der Sicherheitsrichtlinie vorgenommen wurde. In Version 2.0 wird allen Assemblys, die aus dem GAC geladen werden, FullTrust gewährt, unabhängig von der Sicherheitsrichtlinie. Diese Leistungsoptimierung war möglich, da aus dem GAC geladene Assemblys nur selten mit teilweiser Vertrauenswürdigkeit ausgeführt wurden. Beachten Sie diese Änderung, wenn Sie Assemblys bislang auf diese Weise ausgeführt haben!

Mehrere Berechtigungen steuern den Zugriff auf die neuen Features in .NET Framework 2.0. SmtpPermission steuert beispielsweise den Zugriff auf die clientseitige SMTP-Funktionalität, die durch den neuen System.Net.Mail-Namespace bereitgestellt wird.

Eine neue, sehr nützliche Berechtigung ist DataProtectionPermission zur Steuerung, welcher Code die DPAPI-Klassen ProtectedData und ProtectedMemory verwenden darf. Dies ist wirklich wichtig. Von einer nicht vertrauenswürdigen Quelle heruntergeladener Code sollte nicht die CONFIG-Datei entschlüsseln können, die gerade verschlüsselt wurde.

Zusammenfassung

Version 2.0 von .NET Framework ist ein Segen für Entwickler, die sich mit Sicherheit beschäftigen. Ich habe die Arbeit dieses Teams nur oberflächlich behandelt. Der Umfang der Änderungen ist mindestens so groß wie bei ASP.NET 2.0.

Senden Sie Fragen und Kommentare an Keith an  briefs@microsoft.com (in englischer Sprache).

Der Autor

Keith Brown ist Mitgründer von Pluralsight, einem Microsoft .NET-Schulungsanbieter. Keith ist der Autor des Pluralsight-Kurses "Applied .NET Security" sowie mehrerer Bücher, einschließlich The .NET Developer's Guide to Windows Security, das gedruckt (Addison-Wesley Professional, 2004) und im Internet erhältlich ist. Weitere Informationen finden Sie unter www.pluralsight.com/keith.