DEVELOPER 08.11.2005, 10:37 Uhr

Sicherheit in .NET 2.0

Sicherere verteilte Anwendungen unter Windows zu erstellen, war noch nie so einfach wie mit .NET 2.0.
Bereits .NET 1.x wurde mit Sicherheit im Hinterkopf designed. Dafür sprechen viele grundlegende Einrichtungen wie Strong Names, Rollen-basierte Sicherheit, CAS und Kryptographie. Doch um «richtige» Anwendungen zu schreiben, die heutigen Anforderungen genügen, und sich dabei vernünftig in die Windows Sicherheits-Infrastruktur integrieren, muss ein Entwickler immer noch tief in die Win32 und COM Trickkiste greifen. .NET 2.0 wird diese Situation erheblich verbessern, und wartet mit einer Reihe neuer Security APIs auf, mit denen ein Sicherheits-orientierter Programmierer seine wahre Freude haben wird. Windows Security Als kluger Entwickler integriert man sich weitest möglich in die Plattform, auf der die Software auch zum Einsatz kommt. Windows besitzt bereits eine exzellente Sicherheits-Infrastruktur und es gibt keinen Grund das Rad neu zu erfinden. Interessanterweise wurde genau dieser Teil des Windows APIs in 1.1 sehr stiefmütterlich behandelt. Der Namensraum System.Security.Principal kennt nun endlich eine Repräsentation für Windows Accounts (Benutzer, Gruppen und Maschinen). Die Klasse SecurityIdentity kapselt die Maschinen-lesbare Form eines Accounts (SID) und die Klasse NTAccount stellt diese Information im vertrauten «Authority\Benutzer»-Format dar. Das Konvertieren zwischen den beiden Formaten ist mit der Translate-Methode leicht möglich. Weiterhin ist mit dem neuen Enum WellKnownSids nun der Zugriff auf alle «bekannten» SIDs in Windows sichergestellt. Das nachfolgende Codebeispiel zeigt die Konvertierung in beide Richtungen, sowie den Zugriff auf eine «well known» SID: LISTING 1 private static string getSid(string username) { NTAccount account = new NTAccount(username); SecurityIdentifier sid = (SecurityIdentifier)account.Translate (typeof(SecurityIdentifier)); return sid.Value; } private static string getLocalAdminGroup() { SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinAdministratorsSid, null); NTAccount acc = (NTAccount)sid.Translate(typeof(NTAccount)); return acc.Value; } Der Autor , Dominik Baier, ist unabhängiger Security Consultant und betreut die Sicherheits-Kurse bei Developmentor, einer Entwickler-Trainings-Firma Somit ist auch der Weg für den Zugriff auf Windows ACLs geebnet. Unterstützt werden sowohl Zugriffs- als auch Audit-Einträge sowie das Besitzerkonzept. ACLs werden von den File-, Directory-, Registry-, AutoResetEvent-, Mutex- und Semaphore-Klassen unterstützt. Das Konvertieren in und aus dem etwas kryptischen SDDL-Format ist auch enthalten. Somit gibt es nun eine einfache Möglichkeit ACLs, z.B. in einer Installations-Routine zu setzen oder zu modifizieren. Eine sehr unauffällige Neuerung ist, dass Microsoft das Verhalten von Multi-Threading in Bezug auf Security geändert hat. In 1.1 wurde beispielsweise nicht von allen APIs Thread.CurrentPrincipal in neue Threads kopiert (nämlich nur von Thread.Start und Delegate.BeginInvoke). Dies führt bei Multi-Threaded-Systemen, die auf Rollen-basierter Sicherheit aufbauen zu schwer erklärbaren Effekten. Übrigens, wenn Sie unter 1.1 im impersonierten Zustand einen neuen Thread starten, wird der Thread-Token nie kopiert, und der neue Thread wird mit Prozess-Identität ausgeführt. Die gute Nachricht ist, .NET 2.0 ändert dieses Verhalten, und alle APIs funktionieren nun wie erwartet. Zwei kleinere Neuerungen, die einem aber in der Praxis enorm das Leben erleichtern, sind eine neue Überladung von WindowsIdentity.GetCurrent(bool), die Auskunft darüber gibt, ob man gegenwärtig impersoniert. Die Debugger Pseudo-Variable $user liefert genaue Informationen über Prozess- und Thread-Identität. Besonders beim Entwickeln von Serveranwendungen ist dies sehr nützlich. Authentifizierungs-Protokolle NET 2.0 bietet jetzt auch volle Unterstützung von SSPI (Security Service Provider Interface). Dies beinhaltet die Netzwerk-Authentifizierungs--Protokolle NTLM, Kerberos und SSL. Diese Funktionalität ist elegant in einer neuen Stream-Klasse mit Namen «AuthenticatedStream» gekapselt Diese Klasse kann einen vorhandenen «NetworkStream» (z.B. ein Socket) wrappen und ermöglicht es, jede beliebige Netzwerk-Kommunikation zu schützen. Das folgende Codebeispiel zeigt einen einfachen Client und Server. Diese Klasse wird übrigens auch vom TCP-Channel in Remoting verwendet, was nun endlich erlaubt auch diese Kommunikation vernünftig zu schützen. LISTING 2 static void Main(string[] args) { // TCP/IP Connection aufbauen TcpClient client = new TcpClient(); client.Connect("localhost", 4242); // Socket mit NegotiateStream wrappen NegotiateStream kerb = new NegotiateStream(client.GetStream()); // Authentifizierung kerb.AuthenticateAsClient( CredentialCache.DefaultNetworkCredentials, "dbaier/leastprivilege", ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Impersonation); } LISTING 3 ((LISTING 3)) (Server) static void Main(string[] args) { // Socket öffnen TcpListener listener = new TcpListener(4242); listener.Start(); Console.WriteLine("Warten auf Verbindungen..."); TcpClient client = listener.AcceptTcpClient(); // Socket mit NegotiateStream wrappen NegotiateStream kerb = new NegotiateStream(client.GetStream()); // Authentifizierung kerb.AuthenticateAsServer( CredentialCache.DefaultNetworkCredentials, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Impersonation); // WindowsIdentity Objekt das den Client repräsentiert Console.WriteLine("Client Identity: {0}", kerb.RemoteIdentity.Name); } Symmetrische Kryptografie .NET 2.0 bietet im Bereich Kryptografie eine breitere Unterstützung von Standards. Allen voran ist nun der W3C Standard für XML Verschlüsselung und Signaturen integriert. Für das Ableiten von Schlüsseln aus Passwörtern oder das Speichern von Passwörten als Hash wird nun PBKDF2 unterstützt (Password Based Key Derivation Function beschrieben in RFC 2898). Weiterhin kann man .NET jetzt auch so konfigurieren, dass nur FIPS-konforme Verschlüsselungs-Algorithmen benutzt werden können. Der eingebaute Kryptographiedienst von Windows (DPAPI - Data Protection API) war vor 2.0 nur über P/Invoke erreichbar. Die Klasse ProtectedData erlaubt es Ihnen nun Daten zu verschlüsseln, ohne ein manuelles Schlüsselmanagement implementieren zu müssen. Unter der Haube wird dieser API auch verwendet, um das neue Protected-Configuration-Feature zu ermöglichen. Damit können Sie den Inhalt von .NET Konfigurations-Dateien verschlüsseln. Zertifikate und PK-Kryptografie Windows speichert Zertifikate und private Schlüssel im so genannten Certificate Store. Standardsoftware wie Internet Explorer oder Outlook benutzen diesen Systemdienst. Für .NET Entwickler gab es, bis auf den Einsatz der etwas angestaubten CAPICOM COM-Komponente, keine Möglichkeit, diese Dienste zu nutzen. Der neue Namensraum System.Security.Cryptography.X509 hat nun eine komplette Unterstützung für diese Technologie. Weiterhin sind auch alle Standard PKCS (Public Key Cryptography Standard) Objekte wie EnvelopedData oder SignedData enthalten. Mit diesem API lassen sich jetzt echte Zertifikats-basierte Systeme entwickeln. Wie bereits vorher erwähnt, gehört hier auch die Unterstützung für das Protokoll SSL dazu. Deployment .NET 1.1 bietet mit dem No-Touch-Deployment (NTD) ein Konzept, mit dem man Anwendungen von einem zentralen File- oder Web-Server starten kann. In der Praxis stellten sich die dabei zum Einsatz kommenden CAS-Richtlinien als zu restriktiv heraus. Das Ergebnis war, das man NTD entweder gar nicht nutzte, oder die Sicherheit soweit lockerte, dass das ganze Konzept ad absurdum geführt wurde. Mit ClickOnce führt Microsoft in 2.0 eine neue Technik ein, die diese Probleme beheben soll. Mit so genannten Application Manifests werden die Security-Bedürfnisse einer Anwendung definiert. Wird die Anwendung nun gestartet, evaluiert ClickOnce, ob diese Bedürfnisse im Widerspruch zu den lokal definierten Security-Policies stehen. Ist dies der Fall, bekommt der Benutzer die Chance, die Rechte der Anwendung selbst zu erhöhen. Sie haben richtig gehört, der Endanwender trifft nun Sicherheitsentscheidungen. Um diese Technik auch für Firmenumgebungen attraktiv zu machen, lässt sich das genaue ClickOnce Verhalten über Active Directory Gruppenrichtlinien und die Registry konfigurieren. . Zum Ermitteln der benötigten CAS Permissions einer Anwendung wird in 2.0 ein sehr nützliches Tool namens PermCalc.exe ausgeliefert. Dieses Tool analysiert ein Assembly und liefert die notwendigen IPermission-Elemente zurück. Code Access Security CAS hat einige Detail-Verbesserungen erfahren. Wohl am augenscheinlichsten ist, das Assemblies im GAC nun immer mit FullTrust ausgeführt werden (unabhängig von der Policy für den lokalen Rechner). Dazu wurde eine neue GacMembershipCondition eingeführt. Weiterhin erfüllen nun Full Trust Assemblies alle Rechteanforderungen implizit. So wurden z.B. IdentityPermissions unter 1.1 selbst unter Full Trust geprüft, dies ist in 2.0 nicht mehr der Fall. Weiterhin kann man mit dem neuen SecurityTransparent Attribut Assemblies markieren, die immer im Sicherheitskontext des Aufrufers laufen sollen. In diesen Assemblies ist es beispielsweise nicht mehr erlaubt Modifikation am Stack Walk durchzuführen. Dies soll Code Audits und die Entscheidung, ob ein Assembly von teilweise vertrauenswürdigem Code aufrufbar ist, erleichtern. Fazit Jeder Entwickler, der bislang das Gefühl hatte, Microsoft würde ihm allerlei Steine beim Entwickeln von sicherer Software in den Weg legen, kann sich auf .NET 2.0 freuen. Bis auf einige wenige Features sind nun alle Security APIs managed abgebildet und Detailverbesserung führen zu stabilerem und performanterem Code. Viel Spass damit.Dominick Baier


Das könnte Sie auch interessieren