Secure .NET Development Autor: Martin Schagerl Letzte Änderung am 10.07.2014 Version 1.1 Lexon e.U., Inh. Martin Schagerl, Holzing 52, A – 3254 Bergland T: +43 / 676 / 7119622, E: [email protected], I: http://www.lexon.at Secure .NET Development Kurzfassung In dieser Arbeit werden Schwachstellen sowie Fehler aufgezeigt, welche beim Entwickeln von .NET Anwendungen entstehen können. Um die Sicherheit von Applikationen zu erhöhen, werden entsprechende Gegenmaßnahmen und Lösungen erarbeitet, welche sowohl theoretisch also auch praktisch vorgestellt werden. Software Entwickler können die Ergebnisse für bestehende und für neue Projekte nutzen. Das .NET Framework bietet grundsätzlich sehr viel Sicherheitsfeatures an, jedoch müssen diese richtig implementiert und benutzt werden. Dadurch kann die Qualität einer Software gesteigert werden, wodurch spätere Schäden verhindert werden können. Typische Schwachstellen in Webapplikationen wie Cross-Site Scripting, SQL Injection oder Direct Object References werden analysiert und durch .NET Features behoben. Auch für die Verwendung von WCF oder ASP.NET Webservices werden Sicherheitsmechanismen präsentiert. Da das .NET Framework sehr gut in das Betriebssystem integriert ist, wird gezeigt, wie auf den Zertifikatsspeicher zugegriffen wird und dies für kryptografische Verfahren genutzt werden kann. Dazu werden sowohl symmetrische als auch asymmetrische Algorithmen behandelt, um den Schutz von sensiblen Daten zu gewährleisten. Zusätzlich wird das Thema Reverse Engineering aufgegriffen, damit Programmroutinen und hartcodierte Informationen nicht aufgedeckt werden können. Aber auch Techniken zum Schützen von Konfigurationsdaten wie beispielsweise dem ConnectionString werden besprochen. Die Ergebnisse dieser Arbeit bieten einen guten Leitfaden zum sicheren Entwickeln und Bereitstellen von .NET Anwendungen. Abstract This paper describes vulnerabilities and errors, which may occur in developing .NET applications. To increase the security level of applications, techniques and solutions for preventing security leaks in software products are presented. For better understanding, the theoretical aspects will be explained with the help of additional examples. Software developers may use the results for existing and new .NET projects. Basically the .NET framework offers a lot of security features, but they must be implemented and used in a correct way. With the use of these features the quality of software can be increased and subsequent damages prevented. Typical vulnerabilities of web applications such as cross-site scripting, SQL injection or direct object references will be analyzed and resolved with the help of built-in .NET features. The thesis also presents mechanisms for WCF and ASP.NET web services. Due to the fact that the .NET framework is well integrated into the operating system, this paper shows a way to use the Windows certificate store for cryptographic tasks. To ensure the protection of sensitive data, symmetric and asymmetric algorithms will be explained and implemented. Additionally the topic "reverse engineering" is picked up. By following the result presented, uncovering of program routines and hardcoded information can be avoided. Additionally there will be a discussion on techniques for protecting configuration data, such as connection strings. All in all this thesis provides a best practice guide for developing and deploying secure .NET applications. 2 Secure .NET Development Inhaltsverzeichnis 1. EINLEITUNG...................................................................................................................................... 6 1.1. 1.2. 1.3. MOTIVATION UND RELEVANZ ................................................................................................................. 6 ZIELSETZUNG ....................................................................................................................................... 6 AUFBAU DER ARBEIT............................................................................................................................. 7 2. FACHLICHES UMFELD VON .NET .................................................................................................. 8 2.1. 2.2. 2.3. .NET ARCHITEKTUR ............................................................................................................................. 8 ENTITY FRAMEWORK .......................................................................................................................... 10 LINQ ................................................................................................................................................. 11 3. WEB SECURITY .............................................................................................................................. 13 3.1. 3.1.1. 3.1.2. 3.1.3. 3.2. 3.2.1. 3.2.2. 3.2.3. 3.3. 3.4. 3.5. 3.6. CROSS SITE SCRIPTING (XSS)........................................................................................................... 13 Reflected XSS .............................................................................................................................. 13 Stored XSS ................................................................................................................................... 15 DOM based XSS .......................................................................................................................... 17 SQL INJECTION .................................................................................................................................. 17 Unsichere Datenbankzugriffe ....................................................................................................... 17 Sichere Datenbankzugriffe ........................................................................................................... 19 Informationen einer Datenbank ermitteln ..................................................................................... 20 DIRECT OBJECT REFERENCE .............................................................................................................. 23 CROSS-SITE-REQUEST-FORGERY (CSRF) .......................................................................................... 25 AUTHENTIFIZIERUNG ........................................................................................................................... 28 ASP.NET W EB API ........................................................................................................................... 32 4. WINDOWS COMMUNICATION FOUNDATION (WCF) .................................................................. 34 4.1. 4.2. 4.3. ENDPOINTS ........................................................................................................................................ 34 SICHERHEITSMECHANISMEN ................................................................................................................ 37 WCF VS. ASP.NET W EB API............................................................................................................. 39 5. KRYPTOGRAPHIE .......................................................................................................................... 40 5.1. SYMMETRISCHE VERFAHREN............................................................................................................... 40 5.1.1. Diffie-Helman Protokoll ................................................................................................................. 44 5.2. ASYMMETRISCHE VERFAHREN............................................................................................................. 46 5.2.1. Verschlüsselung ........................................................................................................................... 46 5.2.2. Digital Signieren............................................................................................................................ 48 5.3. DIGITALE ZERTIFIKATE ........................................................................................................................ 50 5.3.1. Verschlüsseln ............................................................................................................................... 51 5.3.2. Digital Signieren............................................................................................................................ 53 6. REVERSE ENGINEERING .............................................................................................................. 56 6.1. GEGENMAßNAHMEN ............................................................................................................................ 58 7. DEPLOYMENT ................................................................................................................................ 60 7.1. KONFIGURATIONSDATEN ..................................................................................................................... 60 7.1.1. Clientanwendungen ...................................................................................................................... 60 3 Secure .NET Development 7.1.2. Webanwendungen ........................................................................................................................ 60 7.2. STRONG NAMES ................................................................................................................................. 61 7.3. CLICKONCE-BEREITSTELLUNG ............................................................................................................ 63 8. KONZEPTIONIERUNG EINES SECURE CODING DEMONSTRATORS ...................................... 65 8.1. 8.2. 8.3. W EB SECURITY .................................................................................................................................. 65 KRYPTOGRAPHIE ................................................................................................................................ 66 WCF ................................................................................................................................................. 67 9. ZUSAMMENFASSUNG & AUSBLICK............................................................................................ 68 9.1. W EITERE FEHLERQUELLEN ................................................................................................................. 68 Abbildungsverzeichnis Abbildung 1: .NET Architektur ....................................................................................................................... 9 Abbildung 2: Aufbau von Entity Framework [13] ......................................................................................... 11 Abbildung 3: Webseite für Reflected XSS Angriff ....................................................................................... 14 Abbildung 4: Ergebnis eines Relected XSS Angriffs .................................................................................. 14 Abbildung 5: Eingabe für eine Stored XSS Attacke .................................................................................... 16 Abbildung 6: Ausführung eines Stored XSS Code ..................................................................................... 16 Abbildung 7: Nicht ausgeführte SQL Injection ............................................................................................ 18 Abbildung 8: Ausgeführte SQL Injection ..................................................................................................... 19 Abbildung 9: Blind SQL Injection - Datenbanknamen ermitteln .................................................................. 23 Abbildung 10: CSRF anfällige Webapplikation ........................................................................................... 25 Abbildung 11: Inhalt der CSRF präparierten Webseite ............................................................................... 27 Abbildung 12: Cookie durch die AntiForgeryToken() Funktion ................................................................... 28 Abbildung 13: WCF Kommunikation im Klartext ......................................................................................... 38 Abbildung 14: Schlüsselaustausch abhören ............................................................................................... 44 Abbildung 15: Benutzerzertifikatsspeicher .................................................................................................. 51 Abbildung 16: E-Mail Signatur überprüfen .................................................................................................. 54 Abbildung 17: Dekompilierte Applikation .................................................................................................... 57 Abbildung 18: Originaler Source Code ....................................................................................................... 57 Abbildung 19: Reverse Engineering nach Obfuscating .............................................................................. 59 Abbildung 20: Signieren einer .NET Bibliothek ........................................................................................... 62 Abbildung 21: Information einer Assembly setzen ...................................................................................... 63 Abbildung 22: Exception bei manipulierten Bibliotheken ............................................................................ 63 Abbildung 23: Applikation mittels ClickOnce bereitstellen .......................................................................... 64 Abbildung 24: Herkömmlicher Ablauf des Web Security Demonstrators ................................................... 66 Abbildung 25: Angriffsvektoren des Web Security Demonstrators ............................................................. 66 Listings Listing 1: Herkömmliche SQL Abfrage ........................................................................................................ 11 4 Secure .NET Development Listing 2: LINQ Abfrage ............................................................................................................................... 12 Listing 3: Verhindern von gefährlichen Ausgaben in der View ................................................................... 15 Listing 4: Verhindern von gefährlichen Eingaben am Controller................................................................. 15 Listing 5: Unsicherer Datenbankzugriff ....................................................................................................... 18 Listing 6: Entity Framework - LINQ Abfrage ............................................................................................... 20 Listing 7: Nicht parametrisierte SQL Anweisung ........................................................................................ 20 Listing 8: Parametrisierte SQL Anweisung ................................................................................................. 20 Listing 9: Benutzerdefinierte Fehlermeldungen .......................................................................................... 21 Listing 10: Blind SQL Injection – Anzahl der Spalten ermitteln................................................................... 22 Listing 11: Berechtigung für Direct Object Reference überprüfen .............................................................. 24 Listing 12:HTML Code der CSRF anfälligen Webseite ............................................................................... 26 Listing 13: CSRF präparierte Webseite ...................................................................................................... 26 Listing 14: Implementieren der AntiForgeryToken() Funktion..................................................................... 27 Listing 15: HTML Code durch die AntiForgeryToken() Funktion ................................................................ 27 Listing 16: Attribut zum Überprüfen des CSRF Token ................................................................................ 28 Listing 17: Authorize Attribut ....................................................................................................................... 31 Listing 18: Implementierung der Forms Authentication .............................................................................. 31 Listing 19: OData - Anzahl der Datensätze einschränken .......................................................................... 33 Listing 20: OData - Operationen einschränken ........................................................................................... 33 Listing 21: Service Contract ........................................................................................................................ 35 Listing 22: WCF Endpoint (Service) ............................................................................................................ 36 Listing 23: WCF Endpoint (Client) ............................................................................................................... 36 Listing 24: WCF mit Transportsicherheit ..................................................................................................... 38 Listing 25: TCP Server für AES Kommunikation ........................................................................................ 41 Listing 26: TCP Client für AES Kommunikation .......................................................................................... 43 Listing 27: Diffie-Hellman Implementierung (Client) ................................................................................... 45 Listing 28: Diffie-Hellman Implementierung (Server) .................................................................................. 45 Listing 29: RSA Verschlüsselung (Server) .................................................................................................. 47 Listing 30: RSA Verschlüsselung (Client) ................................................................................................... 47 Listing 31: RSA Signatur erstellen .............................................................................................................. 48 Listing 32: RSA Signatur überprüfen .......................................................................................................... 49 Listing 33: Verschlüsseln mit Zertifikaten.................................................................................................... 52 Listing 34: Entschlüsseln mit Zertifikaten .................................................................................................... 53 Listing 35: Signatur mit einen Zertifikat erstellen ........................................................................................ 54 Listing 36: Signatur überprüfen ................................................................................................................... 55 Listing 37: Demonstrator: Start des gewünschten Verschlüsselungsalgorithmus ...................................... 67 Tabellenverzeichnis Tabelle 1: Ablauf einer Forms Authentication [27] ...................................................................................... 30 Tabelle 2: Technologien von WCF [33, p. 7] .............................................................................................. 34 Tabelle 3: WCF Webservice vs. ASP.NET Web API [37] ........................................................................... 39 Tabelle 4: Funktionalitäten der Demo Webapplikation ............................................................................... 65 5 Secure .NET Development 1. Einleitung 1.1. Motivation und Relevanz Heutzutage steht es sicherlich außer Frage, dass eine sichere Software von enormer Bedeutung ist. Dennoch gibt es zahlreiche Sicherheitslücken in bestehenden sowie neuentwickelten Softwareprodukten. Ein Grund dafür ist, dass die Entwicklung von sicherer Software mit Zeitaufwand und somit mit Kosten verbunden ist. Da Kunden meist nur die korrekte Funktionalität und eventuell das Aussehen einer Anwendung bewerten, werden Sicherheitsaspekte von Entwicklern häufig ignoriert. Diese Kosteneinsparungen können je nach Größe und Art der Software einen enormen finanziellen Schaden bedeuten. Um ein paar Zahlen zu nennen: Laut einer Studie mit 150 Organisationen, kostet alleine die Sanierung einer einzelnen Schwachstelle durchschnittlich 300.000 $. [1] Im Jahr 2007 hat schlecht entwickelte Software einen Schaden von 180 Milliarden Dollar in der USA angerichtet. [2] Neben diesen hohen Kosten können Sicherheitslücken das Image eines Unternehmens zerstören, wenn beispielsweise persönliche Daten bzw. Kreditkarteninformationen von Angreifern aufgedeckt werden. Viele Unternehmen, Institute, Organisationen und öffentliche Einrichtungen investieren viel Geld in ihre ITInfrastruktur, ohne Rücksicht auf Softwaresicherheit zu nehmen. Ohne Frage haben Systeme wie beispielsweise Firewalls ihre Berechtigung und können bestimmte Angriffe abwehren, jedoch sind diese vollkommen nutzlos, wenn eine Softwareschwachstelle aktiv ausnutzbar ist. Eine gute Sicherheitspolitik ist gegeben, wenn in allen IT-Bereichen (Infrastruktur, Software, Clients, usw.) ein hohes Sicherheitsniveau erreicht wird. Um eine sichere Software zu entwickeln, empfiehlt es sich, auf bestehende Frameworks zurückzugreifen, welche bewährte Sicherheitskonzepte anbieten. Solche Frameworks machen Anwendungen nicht nur sicherer, sondern beschleunigen zusätzlich ihre Entwicklung. Es kann nämlich auf viele Funktionalitäten zurückgegriffen werden, ohne diese neu entwickeln zu müssen. Microsoft, einer der größten Softwarehersteller der Welt, stellt dazu das .NET Framework für Entwickler/innen zur Verfügung. [3, p. 11] Einer der großen Vorteile dieses Frameworks ist, dass es in unterschiedlichen Anwendungstypen verwendet werden kann: Konsolenanwendungen Desktopanwendungen Webanwendungen Webservices Dadurch können Entwickler einerseits mit einem Know-How viele unterschiedliche Anwendungen erstellen, und andererseits kann ein Code in mehreren Applikationen wiederverwendet werden. 1.2. Zielsetzung Im Vergleich zu klassischen Programmiersprachen wie C oder C++ bietet das .NET Framework viel Unterstützung bei der Entwicklung sicherer Applikationen. Trotzdem beinhalten .NET Applikationen Sicherheitsschwachstellen, verursacht z.B. durch 6 Secure .NET Development Verwendung unsicherer Aufrufe (z.B. Ausgabe ohne Codierung) unsichere Verwendung von Funktionen Fehler in der Logik (z.B. Integer Overflows) Aufrufe von Legacycode fehlerhafte Verwendung von Sicherheitsfunktionalität (z.B. Authentisierung, Autorisierung, Verschlüsselung) Das .NET Framework bietet jede Menge Sicherheitsfunktionalitäten an, welche jedoch nicht immer automatisch zur Wirkung kommen, weil diese explizit von Programmierer/innen implementiert werden müssen. Daher besteht trotz .NET die Möglichkeit, fatale Fehler zu machen, wodurch Sicherheitslücken entstehen können. Aus diesem Grund ist es Aufgabe der Entwickler, die mitgelieferten Features richtig einzusetzen, um Applikationen sicherer zu machen. In dieser Arbeit werden dazu typische Schwachstellen von .NET Applikationen untersucht und diese mittels .NET Unterstützung behoben. Es wird gezeigt, was bei den Sicherheitsfunktionen beachtet werden muss beziehungsweise welche Funktionen für welchen Zweck geeignet sind. Die konkrete Forschungsfrage dieser Arbeit lautet daher: Wie kann das .NET Framework sinnvoll genutzt werden, um sichere, stabile und zukunftsorientierte Applikationen zu entwickeln? 1.3. Aufbau der Arbeit In Kapitel 2 wird ein fachlicher Einstieg geschaffen, damit die späteren Ansätze besser verstanden werden können. Dabei wird ein Überblick über das Framework dargelegt und später verwendete Technologien werden kurz angesprochen und erklärt. Im Hauptteil wird veranschaulicht, wie das .NET Framework in den Bereichen Web Security, WCF, Kryptographie und Deployment richtig eingesetzt werden sollte. Es werden häufige Entwicklungsfehler aufgezeigt und dazu Best Practice Lösungen theoretisch sowie praktisch erläutert. Weiter wird im Hauptteil der Punkt Reverse Engineering behandelt, um zu zeigen, wie einfach und gefährlich das Dekompilieren von Anwendungen ist. Auch hierzu werden entsprechende Gegenmaßnahmen präsentiert. Damit Anwendungen richtig bereitgestellt werden, wird ein kurzer Einblick in das Deployment von .NET Applikationen gegeben. Im letzten Kapitel werden die wichtigsten Punkte zusammengefasst und ein Ausblick gegeben. 7 Secure .NET Development 2. Fachliches Umfeld von .NET Das .NET Framework ist eine von Microsoft entwickelte Laufzeitumgebung, welche eine Sammlung von Klassenbibliotheken und Programmschnittstellen enthält. Das Framework ist im vollen Umfang nur für Windows verfügbar, jedoch gibt es Open-Source-Projekte wie Mono, welche es erlauben, .NET Applikationen auch auf anderen Plattformen wie Linux auszuführen. [4] [5] In den folgenden Kapiteln werden der Aufbau des Frameworks sowie .NET Technologien näher erläutert, um die späteren Ansätze besser verstehen zu können. 2.1. .NET Architektur Programmiersprachen Bevor eine .NET Anwendung entwickelt wird, muss entschieden werden, welche Programmiersprache eingesetzt werden soll. Das Framework wurde von Beginn an dafür entwickelt, dass Entwickler in unterschiedlichen Programmiersprachen arbeiten können. Es kann im Prinzip jede Sprache verwendet werden, für die es einen Language Compiler gibt, welcher die Hochsprache in die Common Intermediate Language (CIL) übersetzen kann. Eine Liste aller Sprachen findet man unter http://www.itvisions.de/dotnet/produkte/sprachen.aspx Die Wahl der Programmiersprache ist abhängig von den vorhandenen Programmierkenntnissen sowie dem Einsatzbereich der zu erstellenden Anwendung. Bei Bedarf ist es auch möglich, mehrere Sprachen in einer Anwendung zu kombinieren. [6] Alle hier gezeigten praktischen Beispiele werden mit der Programmiersprache C# demonstriert, da mittels dieser Sprache alle Vorteile von .NET Framework vollständig genutzt werden können. Das .NET Framework ermöglicht die Zusammenarbeit zwischen den unterschiedlichen Sprachen, wodurch ein Programmcode aufgerufen werden kann, der in einer anderen .NET Sprache geschrieben worden ist. Zusätzlich können Klassen vererbt werden, die in anderen Sprachen entwickelt worden sind. Dieser Vorteil wird durch die Common Language Specification sowie dem Common Type System (CTS) ermöglicht. [7] Das Common Type System definiert, wie Datentypen deklariert, verwendet und in der Common Language Runtime verwaltet werden. Dies sorgt für eine Vereinheitlichung der Datentypen, damit diese in allen benutzten Sprachen interoperabel sind. [8] Anwendungstypen Wie bereits unter 1.1 angesprochen, können mit dem .NET Framework unterschiedliche Anwendungstypen wie Desktop Anwendungen, Konsolen Anwendungen, Web Anwendungen, Web Services und Windows Services entwickelt werden. Je nach ausgewähltem Anwendungstyp, werden die jeweiligen Bibliotheken aus der Framework Class Library zur Verfügung gestellt. Framework Class Library (FCL) Die Framework Class Library (FCL) ist eine Sammlung von Klassen und Datentypen, welche .NET Anwendungen zum Lesen und Schreiben von Dateien, Zugreifen auf Datenbanken, Entwerfen von grafischen Benutzeroberflächen, Konsumieren von Web-Services usw. nutzen können. Die FCL stellt dabei viele Funktionen der Win32-API in einfachen. NET Objekten dar, die von den .NET Programmiersprachen verwendet werden können. [9] 8 Secure .NET Development Common Intermediate Language (CIL) Das .NET Framework arbeitet – genau wie die Programmiersprache Java - mit einer Zwischensprache. Ein Compiler einer .NET Sprache erzeugt also keinen prozessorspezifischen Maschinencode, sondern einen plattformunabhängigen Bytecode. Dieser Code wird Common Intermediate Language (CIL) genannt – früher sprach man von der Microsoft Intermediate Language (MSIL). [10, pp. 1-2] Erst zur Laufzeit wird der CIL-Code in einen Maschinencode (Native Code) umgewandelt. Der CIL-Code wird dabei nicht wie bei Java interpretiert, sondern von einem sogenannten Just-in-Time-Compiler (JITCompiler) stückweise kompiliert und dann ausgeführt. Dabei berücksichtigt der JIT-Compiler prozessorspezifische Optimierungsmöglichkeiten. Dadurch, dass nicht interpretiert, sondern vor der Ausführung kompiliert wird und der JIT-Compiler sehr schnell arbeitet, ist der Performance-Verlust durch die Intermediation sehr gering. [10, p. 2] Common Language Runtime Die Ausführung einer .NET Anwendung setzt eine Laufzeitumgebung voraus, die sogenannte Common Language Runtime (CLR). Die CLR stellt den JIT-Compiler und zahlreiche andere Dienste bereit, die von allen .NET Programmiersprachen verwendet werden können. Dazu gehören zum Beispiel der Garbage Collector, ein Exception Handling und ein Sicherheitssystem. [11] Der Programmcode, der im Rahmen der CLR ausgeführt wird, heißt Managed Code (verwalteter Code). Der restliche Code wird dann entsprechend Unmanaged Code (nicht-verwalteter Code) genannt. Windows Forms Console Framework Class Library Base Class Library ADO.NET Library WPF, WCF, … Bytecode Laufzeitumgeb Ausführung Language Compiler Anwendungst Web (MVC, Service, Common Intermediate Language Common Language Runtime Betriebssystem / Prozessor Bytecode zu Maschinecode Sprach C#, VBA, J#, F#, … Common Language Specification Common Type System Abbildung 1: .NET Architektur 9 Secure .NET Development 2.2. Entity Framework Übliche Client-Server Applikationen sowie Webanwendungen sind häufig mit einer Datenbank verbunden. Bekannte Datenbanksysteme wie Oracle, MySQL und Microsoft SQL verwalten ihre Daten in Form von Tabellen und Spalten (Relationaler Speicher), während in modernen Programmiersprachen die Datenverwaltung mittels Klassen (Objektorientierter Speicher) durchführen wird. [12, p. 887] Um diese beiden unterschiedlichen Speicherformen zu verbinden, können sogenannte Object-Relational Mapping (ORM) Frameworks wie das Entity Framework (EF) verwendet werden. Eine weitere häufige Anforderung an Anwendungen ist, dass mehrere unterschiedliche Datenbanksysteme unterstützt werden müssen. Wird beispielsweise eine Applikation für mehrere Unternehmen entwickelt, so kann nicht davon ausgegangen werden, dass jedes Unternehmen dieselbe Datenbank im Einsatz hat. Um mit mehreren Datenbanken kompatibel zu sein, müssen Datenbankzugriffe üblicherweise mehrfach geschrieben werden, da SQL Statements zwischen den Systemen unterschiedlich sind. Dies würde nicht nur einen hohen Aufwand bedeuten, sondern auch eine Menge an Nachteile wie Unübersichtlichkeit, Wartungsintensivität und Fehleranfälligkeit mit sich bringen. Auch hier kann das Entity Framework Abhilfe schaffen: Das Framework unterstützt Microsoft SQL Server, Oracle, MySQL und DB2. [12, p. 885] Das EF wurde erstmalig 2008 in das .NET Framework 3.5 integriert und seither stark weiterentwickelt. Seit dem .NET Framework 4 wird es über den Package Manager von Visual Studio NuGet ausgeliefert: http://www.nuget.org/packages/EntityFramework Das Entity Framework kann in zwei verschieden Ansätzen verwendet werden: Code First: Für Anwendungen, für die es noch keine Datenbank gibt. Hier werden zuerst die Klassen geschrieben, welche dann mittels ORM mit der Datenbank verbunden werden. Database First: Für Anwendungen, die auf eine bestehende Datenbank zugreifen. Hier werden die Tabellen und Spalten der bestehenden Datenbank in Klassen konvertiert und mittels ORM verbunden. Alle hier gezeigten praktischen Beispiele werden mit dem Code First Ansatz durchgeführt. In der Abbildung 2 wird die Architektur von Entity Framework gezeigt: In der obersten Schicht befindet sich die Anwendung, wo die Abfragen in einer datenbankunabhängigen Sprache wie LINQ (siehe 2.3) formuliert werden. Die erstellten Statements werden dann vom Entity Client entgegengenommen und auf das Entity Daten Model angewendet. Wenn der Bedarf besteht, auf die Datenbank zuzugreifen, wird die Abfrage an den jeweiligen ADO.NET Provider weitergegeben. Je nach Datenbanksystem wird hier ein anderer Provider verwendet, welcher dann die nativen SQL Befehle zur Datenbank sendet. [12, pp. 880, 881] 10 Secure .NET Development LINQ Natives SQL Abbildung 2: Aufbau von Entity Framework [13] 2.3. LINQ Um Abfragen von der eingesetzten Datenquelle unabhängig zu machen, kann die sogenannten Language Integrated Query (LINQ) eingesetzt werden. Hierbei handelt es sich um eine von Microsoft entwickelte Abfragesprache, die den Zugriff auf Datenstrukturen vereinheitlicht. [14, p. 2] Dadurch macht es bei der Entwicklung einer Anwendung keinen Unterschied, ob die Daten beispielsweise in einer Microsoft SQL oder Oracle Datenbank gespeichert sind. Im Unterschied zu herkömmlichen Datenbankabfragen, wo native SQL Anweisungen als String im Source Code angegeben sind, werden LINQ Anweisungen in den Source Code eingebettet. Dadurch können Fehler bereits beim Kompilieren und nicht erst zur Laufzeit festgestellt werden. [14, p. 14] So können Fehler frühzeitig erkannt und behoben werden. Beispiel einer Abfrage: Herkömmlich 1 SELECT * FROM Customers WHERE Country = 'Italy' Listing 1: Herkömmliche SQL Abfrage 11 Secure .NET Development LINQ 1 2 3 from c in Customers where c.Country == "Italy" select c; Listing 2: LINQ Abfrage Wenn man den Code aus Listing 1 und Listing 2 vergleicht, fällt auf, dass bei LINQ eine Ähnlichkeit zur SQL Sprache besteht. Dadurch fällt es leichter, die neue Abfragesprache zu erlernen. 12 Secure .NET Development 3. Web Security Der Trend der letzten Jahre zeigt, dass Computer Applikationen häufig als Webapplikationen abgebildet werden. Dadurch sind keine zusätzlichen Client-Installationen notwendig, die eingesetzte Anwendung ist von überall erreichbar und Updates können zentral durchgeführt werden. Durch die hohe Verbreitung von mobilen Geräten wie Smartphones und Tablets werden Webapplikationen weiter an Beliebtheit gewinnen, da dadurch Anwendungen plattformunabhängig genutzt werden können. In Gegensatz zu nativen Anwendungen können Webapplikationen in Kombination mit einem Cloud Dienst bei hoher Auslastung automatisch auf mehrere Server skaliert werden, um alle Anfragen ohne Verzögerung beantworten zu können. Dieser Vorgang wäre bei nativen Anwendungen nur mit sehr viel Aufwand möglich. Da Webapplikationen bzw. Webservices in der Regel vom Internet zugänglich sind, haben Sicherheitsmaßnahmen bei der Entwicklung höchste Priorität. Die hier erarbeiteten Sicherheitsaspekte können sowohl für neue als auch für bestehende Webanwendungen übernommen werden. Mit dem .NET Framework können sowohl Webanwendungen als auch Webservices erstellt werden. Bei beiden Formen gibt es unterschiedliche Angriffspunkte, welche berücksichtigt werden müssen. Daher werden in den nachfolgenden Unterkapiteln beide Formen behandelt. 3.1. Cross Site Scripting (XSS) Einer der häufigsten Angriffe auf Webapplikationen wird durch Cross Site Scripting (XSS) Attacken durchgeführt. Diese Schwachstelle beruht auf einer fehlenden oder unzureichenden Überprüfung der Daten vor der Ausgabe durch den Browser. Bei einem Angriff wird versucht, Script Code (z.B. JavaScript) an einen Webserver zu senden, sodass der Schadcode beim nächsten Aufruf im Kontext des Opfers ausgeführt wird. Im Gegensatz zu einer SQL Injection wird hier nicht die Datenbank der Webanwendung angegriffen, sondern der Webserver bzw. der Client selbst. [15, p. 840] Dabei gibt es die drei nachfolgenden XSS Möglichkeiten. 3.1.1. Reflected XSS Hierbei handelt es sich um einen nicht-persistenten XSS Angriff, bei dem eine Benutzereingabe direkt vom Server wieder zurückgeschickt wird. Da die Eingaben dabei nicht gespeichert werden, kann ein Code nur einmal zur Ausführung kommen. [16] Durch das nachfolgende Beispiel soll die Schwachstelle demonstriert werden: Auf einer Webseite gibt es eine Liste, welche durch einen Suchfilter eingeschränkt werden kann. Dabei werden die eingegebenen Suchbegriffe zur Übersichtlichkeit wieder ausgegeben: 13 Secure .NET Development Abbildung 3: Webseite für Reflected XSS Angriff Beim Klicken auf den „Filter“ Button werden im Query String die Suchparameter angegeben: http://<domain>/Mile?searchEventName=XSS&searchEventType= Um nun eine Reflacted XSS Attacke durchzuführen, könnte man einen Skript Code in den Query String einfügen und diese präparierte URL per E-Mail versenden: http://<domain>/Mile?searchEventName=<script>alert(“Reflected XSS Attacke“);</script>&searchEventType= Der Aufruf dieses Links würde zum folgenden Ergebnis führen Abbildung 4: Ergebnis eines Relected XSS Angriffs Damit diese Schwachstelle in .NET Webapplikationen verhindert wird, müssen folgende Aktionen durchgeführt werden: View Um einen Inhalt vom Server auszugeben, @Html.Raw(ViewBag.SearchInput) wird häufig folgende Form verwendet: Durch das @Html.Raw (...) wird der übergebene Inhalt eins zu eins an den Browser weitergegeben, wodurch ein Browser einen Script Code interpretieren würde. Um dies zu verhindern, 14 Secure .NET Development muss der Inhalt kodiert werden, um darstellbare HTML Tags zu ersetzen: „<“ &lt; „>“ &gt; typische Zeichen eines Scripts, wie z.B „<“ oder „>“ durch Dies kann durch folgenden Code erreicht werden: 1 <b>Results for:</b> @Html.Encode(ViewBag.SearchInput) Listing 3: Verhindern von gefährlichen Ausgaben in der View Controller Beim Controller darf auf keinen Fall das Methoden Attribut [ValidateInput(false)] gesetzt sein. Wenn dieses Attribut nicht beziehungsweise auf True gesetzt ist, werden die übergebenen Parameter auf Script Code überprüft. Sobald ein verdächtiger Inhalt übergeben wird, wird automatisch eine Exception ausgelöst. 1 2 3 4 5 [ValidateInput(true)] public ActionResult Index(string searchEventType, string searchEventName) { … } Listing 4: Verhindern von gefährlichen Eingaben am Controller 3.1.2. Stored XSS Im Unterschied zur Reflected XSS wird bei der Stored XSS der Schadcode auf dem Webserver bzw. in der Datenbank der Webapplikation gespeichert, wodurch er bei jeder Anfrage zurückgeliefert wird und zur Ausführung kommen kann. [16] Da der Schadcode mehrmals zur Ausführung kommen kann, ist dieser Angriff wesentlich gefährlicher als bei Reflected XSS. Store XSS Attacken sind möglich, sobald eine Webapplikation Benutzerdaten entgegennimmt und ohne Prüfung speichert und diese später wieder ausliefert. Das nachfolgende Beispiel soll die Schwachstelle praktisch demonstrieren: Auf einer Webseite können Benutzereingaben an den Server gesendet werden. Hier wird in unserem Fall ein einfacher JavaScript Code eingegeben und übermittelt. 15 Secure .NET Development Abbildung 5: Eingabe für eine Stored XSS Attacke Sobald die neuen Daten abgefragt werden, kommt der JavaScript Code zur Ausführung Abbildung 6: Ausführung eines Stored XSS Code Natürlich würde ein geschickter Angreifer anstelle des Öffnens eines Popup eine andere Aktion durchführen, wie beispielsweise die Cookies auslesen. Dadurch könnte ein Angreifer beispielsweise die Session eines anderen Benutzers übernehmen. Um diese Schwachstelle in .NET Webapplikationen zu verhindern, müssen dieselben Gegenmaßnahmen wie bei den Reflected XSS durchgeführt werden (siehe 3.1.1). Weiters müssen sichere Methoden für den Datenbankzugriff verwendet werden (siehe 3.2.2) View Alle Ausgaben kodieren. Dadurch werden Script Tags in HTML Tags umgewandelt und werden somit nicht ausgeführt, sondern dargestellt. Controller Auf keinen Fall das Attribut [ValidateInput(false)] weglassen oder den Parameter auf True setzen. setzen, sondern entweder das Attribut 16 Secure .NET Development 3.1.3. DOM based XSS Diese Attacke ist völlig unabhängig vom Webserver der Webseite. Daher können auch statische Webseiten betroffen sein. Bei DOM based XSS wird der Schadcode direkt an den Client übergeben und dort zur Ausführung gebracht, ohne eine Anfrage an den Webserver zu stellen. Dazu könnte beispielsweise der Query String einer URL so verändert werden, dass ein Script Code im Kontext des Opfers ausgeführt wird. [16] Da es sich hierbei um eine Schwachstelle am Client handelt, gibt es von .NET keine Gegenmaßnahmen. Um der Schwachstelle entgegen zu wirken, müssen alle am Client verarbeiteten Daten überprüft bzw. kodiert werden. 3.2. SQL Injection Eine SQL Injection ist eine Attacke gegen Datenbank-basierte Applikationen. Erfolgreiche Angriffe können es einem Angreifer ermöglichen, sich unerlaubt in eine Web-Applikation mit Zugriffsschutz einzuloggen, private Informationen aus einer Datenbank zu entwenden oder Daten zu manipulieren. [17] Der Angreifer versucht dabei, Benutzereingaben so zu formulieren, dass diese Eingaben die Datenbankabfrage verändern, um eigene SQL Anweisungen an die Datenbank zu senden. Der Angriff wird möglich, wenn Eingaben ohne Überprüfungen in die Abfragen übernommen werden. 3.2.1. Unsichere Datenbankzugriffe Es gibt mehrere Möglichkeiten, um aus einer .NET Anwendung auf eine Datenbank zuzugreifen. Einige sind jedoch bereits veraltet und sollten auf keinen Falls mehr benutzt werden. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // create and open SQL connection var connection = new SqlConnection(); connection.ConnectionString = ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString; connection.Open(); // generate select statement string query = "SELECT m.Id, m.Name, m.Amount, m.IsAccepted, m.Comment, e.Name, u.Username"; query += " FROM Miles m INNER JOIN EventTypes e on m.Type_Id = e.Id"; query += " INNER JOIN ApplicationUsers u on m.User_Id = u.Id"; List<string> whereStatements = new List<string>(); if (!IsAdmin) whereStatements.Add("m.User_Id = " + <UserId> + ""); if (!string.IsNullOrEmpty(searchEventName)) whereStatements.Add("m.Name LIKE '%" + searchEventName + "%'"); 17 Secure .NET Development 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 if (!string.IsNullOrEmpty(searchEventType)) whereStatements.Add("m.Type_Id = '" + searchEventType + "'"); for (int i = 0; i < whereStatements.Count; i++) { if (i == 0) query += " WHERE "; else query += " AND "; query += whereStatements[i]; } // execute select statement SqlCommand command = new SqlCommand(query, connection); SqlDataReader reader = command.ExecuteReader(); // process data // ... Listing 5: Unsicherer Datenbankzugriff Im Beispiel von Listing 5 werden folgende Aktionen durchgeführt: Zeile 3 – 6: Die Datenbankverbindung wird instanziiert und mit den Verbindungsdaten konfiguriert, welche aus der web.config ausgelesen werden. Weiteres wird die Verbindung zum Datenbankserver geöffnet. Zeile 9 - 12: Das Select Statement wird zusammengestellt. Zeile 14 – 32: Es wird überprüft, ob ein Filter angegeben wurde. Wenn ja, wird ein entsprechendes Where Statement zur SQL Anweisung hinzugefügt. Zeile 35: Es wird ein SqlCommand Objekt angelegt und mit der Datenbankverbindung sowie dem Select Statement initialisiert. Zeile 36: Das Select Statement wird zur Datenbank gesendet und ausgeführt. Die zurückgelieferten Daten werden im SqlDataReader Objekt abgespeichert. Der Code von Listing 5 kann folgendermaßen angegriffen werden: Sobald die Seite aufgerufen wird, welche die SQL Anweisung von Listing 5 ausführt, werden nur die eigenen Einträge angezeigt. Abbildung 7: Nicht ausgeführte SQL Injection 18 Secure .NET Development Nun kann ein Suchbegriff so formuliert werden, dass damit die SQL Anweisung manipuliert wird und alle Einträge ausgibt. Es könnte beispielsweise nach irgendetwas' or 1=1 -– gesucht werden. Dadurch würde die Variable „query“ von Listing 5 folgenden Inhalt bekommen: SELECT m.Id, m.Name, m.Amount, m.IsAccepted, m.Comment, e.Name, u.Username FROM Miles m INNER JOIN EventTypes e on m.Type_Id = e.Id INNER JOIN ApplicationUsers u on m.User_Id = u.Id WHERE m.User_Id = 2 AND m.Name LIKE '%irgendetwas' or 1=1--%' Da die Zeichen „%‘" am Ende mittels „--" auskommentiert werden, werden diese nicht vom SQL Server ausgeführt, wodurch es zu keinem Syntaxfehler kommt. Daher steht am Schluss der Anweisung 1=1, was immer True liefert und somit auf jede Zeile zutrifft. Abbildung 8: Ausgeführte SQL Injection Damit ein solcher Angriff verhindert werden kann, muss der Zugriff auf die Datenbank geändert werden. Dazu gibt es zwei Möglichkeiten, welche im nächsten Kapitel erklärt werden. 3.2.2. Sichere Datenbankzugriffe Um in .NET Anwendungen mit einer Datenbank zu kommunizieren, wird seitens Microsoft das Entity Framework empfohlen. [18] Wie unter 2.2 beschrieben bietet dieses ORM Framework nicht nur sicherheitsrelevante Vorteile, sondern beschleunigt und erleichtert zusätzlich die Entwicklung. Um den unsicheren Datenbankzugriff aus Listing 5 nun mit dem Entity Framework durchzuführen, muss folgender Code geschrieben werden: 1 2 3 4 5 6 7 8 9 10 ApplicationDbContext context = new ApplicationDbContext(); IQueryable<Mile> miles = context.Mile.AsQueryable(); if (!string.IsNullOrEmpty(searchEventName)) miles = miles.Where(m => m.Name.Contains(searchEventName)); if (!string.IsNullOrEmpty(searchEventType)) miles = miles.Where(m => m.Type.Id.Equals(searchEventType)); if (!IsAdmin) miles = miles.Where(m => m.User.Id.Equals(<UserId>)); return View(miles.ToList()); 19 Secure .NET Development Listing 6: Entity Framework - LINQ Abfrage Im Beispiel von Listing 6 werden folgende Aktionen durchgeführt: Zeile 1: Es wird eine Instanz von der Klasse ApplicationDbContext erzeugt. Diese Klasse ist von DBContext abgeleitet und verfügt über Informationen, wie die Datenbankverbindung, Metadaten des Datenmodels sowie eine Änderungsverfolgung. Zeile 2: Es wird ein Queryable Object mit dem Type Mile erzeugt. Mithilfe dieses Objekts können LINQ Abfragen erstellt werden. Hier werden noch keine Daten von der Datenbank abgefragt. Zeile 3 – 8: Es wird überprüft, ob ein Filter gesetzt wurde. Wenn ja, wird ein entsprechendes LINQ Statement angegeben. Auch hier werden noch keine Daten von der Datenbank abgefragt. Zeile 10: Erst durch die Methode ToList() wird die SQL Anweisung ausgeführt und die Ergebnisse werden zurückgeliefert. Wenn man mit älteren .NET Frameworks (< 3.5 SP1) arbeitet, kann das Entity Framework nicht genutzt werden. [19] Jedoch gibt es auch eine andere Technik zum Verhindern von SQL Injections: Anstatt die Benutzereingaben direkt in die Anweisung einzufügen, kann die Klasse SqlParameter verwendet werden. Dabei werden in der SQL Anweisung Variablen definiert, welche zu einem späteren Zeitpunkt durch die entsprechenden Werte (Benutzereingaben) ersetzt werden. [20] Nicht parametrisiert 1 2 queryString = "SELECT * FROM Miles WHERE User_Id =‘" + userId + "‘ AND Name LIKE ‘%" + name + "%‘" Listing 7: Nicht parametrisierte SQL Anweisung Parametrisiert 1 2 3 4 queryString = "SELECT * FROM Miles WHERE Username=@ID AND Name LIKE @NAME"; command.Parameters.AddWithValue("@ID", userId); command.Parameters.AddWithValue("@NAME ", name); Listing 8: Parametrisierte SQL Anweisung In Listing 7 wird die SQL Anweisung mit einer Zeichenkettenoperation zusammengestellt, wodurch eine SQL Injection möglich wird. Daher sollte die Anweisung mittels Parameter, wie in Listing 8 gezeigt, erstellt werden. In den Zeilen 1 – 2 werden die beiden Variablen „ID“ und „Name“ gesetzt. In den Zeilen 3 – 4 werden diese dann durch die entsprechenden Werte ersetzt. 3.2.3. Informationen einer Datenbank ermitteln Um komplexere SQL Injections durchführen zu können, muss das Schema der Zieldatenbank bekannt sein. Das bedeutet, der Angreifer muss wissen, wie die Tabellen heißen, welche Spalten diese besitzen und wie diese zusammenhängen (Relationen). Da dem Angreifer jedoch in den meisten Fällen das 20 Secure .NET Development Datenbankschema nicht herauszufinden: bekannt ist, wird versucht, dieses mit den nachfolgenden Methoden Analysieren von Fehlermeldungen Bei dieser Methode werden fehlerhafte SQL Anweisungen generiert, um aussagekräftige Fehlermeldungen zu produzieren. Anhand solcher Fehlermeldungen können Tabellennamen, Spaltennamen oder Datentypen entnommen werden. Um dies bei .NET Webapplikationen zu verhindern, sollte immer folgender Eintrag in der web.config vorgenommen werden: 1 2 3 4 5 6 7 8 9 10 <configuration> <system.web> <customErrors defaultRedirect="MyErrorPage.htm" mode="RemoteOnly"> <error statusCode="500" redirect="InternalError.htm"/> </customErrors> </system.web> </configuration> Listing 9: Benutzerdefinierte Fehlermeldungen Dadurch wird bei einem Fehler eine benutzerdefinierte Fehlermeldung ausgegeben. Diese sollte keine technischen Informationen enthalten, sondern nur darüber informieren, dass ein Fehler aufgetreten ist. Im Listing 9 wird in der Zeile 3 die Webseite angegeben, welche diese Fehlermeldung enthält. In der Zeile 4 wir angegeben, dass benutzerdefinierte Fehlermeldungen nur für Remoteclients ausgegeben werden. So werden ASP.NET-Fehlermeldungen weiterhin für den lokalen Host angezeigt, wodurch Administratoren oder Entwickler die detaillierten Fehlermeldungen erhalten. Wie man in den Zeile 6 – 7 sehen kann, können für bestimmte Fehlertypen unterschiedliche Fehlerseiten verwendet werden. Blind SQL Wenn Webapplikationen entweder keine detaillierten Fehlermeldungen liefern, beziehungsweise bei Fehlern gar keine Daten ausgeben (z.B. eine leere Liste), dann können Informationen mithilfe von Blind SQL Injections ermittelt werden. Bei dieser Methode werden systematisch unterschiedliche Kombinationen von Anweisungen ausprobiert und danach die Antworten ausgewertet. [21] Wie in der Abbildung 8 zu sehen ist, konnte eine SQL Injection bereits erfolgreich durchgeführt werden. Doch wir haben noch keine Informationen über die Datenbank selbst erhalten. Wenn wir zum Beispiel wissen möchten, wie viele Spalten beim Filtern der Liste aus Abbildung 8 abgefragt werden, müssten wir zunächst folgende Anfragen generieren: 21 Secure .NET Development Listing 10: Blind SQL Injection – Anzahl der Spalten ermitteln Da die Daten ohne einer Fehlermeldung ausgegeben werden, wissen wir, dass die SQL Anweisung erfolgreich durchgeführt worden ist. Daher fahren wir mit folgenden Anweisungen fort: xyz' xyz' xyz' xyz' xyz' xyz' xyz' order order order order order order order by by by by by by by 2 3 4 5 6 7 8 -------- // Kein Fehler // Kein Fehler // Kein Fehler // Kein Fehler // Kein Fehler // Kein Fehler // Fehler Wir wissen jetzt, dass die Abfrage aus sieben Spalten besteht. Diese Information benötigen wir für die nachfolgenden Schritte. Auf einer MS SQL Datenbank kann der aktuelle Datenbankname mit folgender Anweisung abgefragt werden: SELECT DB_NAME() Da wir nun wissen, wie viele Spalten die Abfrage hat und wie wir den aktuellen Namen der Datenbank auslesen, probieren wir die folgende Anweisung: xyz' union all SELECT DB_NAME(),null,null,null,null,null, null -Mit UNION vereinen wir die Ausgabe der ersten und zweiten Abfrage, wobei die zweite Abfrage den Datenbanknamen ausgibt. Da die Anzahl der Spalten bei beiden Abfragen ident sein muss, werden die restlichen sechs Spalten mit null befüllt. Der Befehl lieferte jedoch leider eine leere Ausgabe. Der Grund dafür könnte sein, dass die erste Spalte nicht für die Ausgabe verwendet wird (es handelt sich wahrscheinlich um eine ID). Aus diesem Grund geben wir den Datenbanknamen in der zweiten Spalte aus: xyz' union all SELECT null, DB_NAME(),null,null,null,null, null -- 22 Secure .NET Development Abbildung 9: Blind SQL Injection - Datenbanknamen ermitteln Wie in Abbildung 9 ersichtlich, konnte der Datenbankname erfolgreich ermittelt werden. Nun können eine Reihe weitere Informationen abgefragt werden: Alle Tabellennamen ermitteln: xyz' union all SELECT null,name,null,null,null,null, null FROM WebSecurity..sysobjects WHERE xtype = 'U' -Alle Spalten der Tabelle Miles ermitteln: xyz' union all SELECT null,COLUMN_NAME,null,null,null,null, null FROM information_schema.columns WHERE table_name = 'Miles' -Wie man sehen kann, hat man beinahe alle Möglichkeiten, um auf die Datenbank zuzugreifen. Es ist aber auch möglich, Datensätze zu löschen oder zu verändern. Alle Einträge aus der Tabelle Miles löschen: xyz'; DELETE FROM Miles -Um alle diese Angriffe zu unterbinden, müssen die Datenbankzugriffe entweder parametrisiert oder mittels Entity Framework durchgeführt werden. (siehe 3.2.2) 3.3. Direct Object Reference Bei Webanwendungen werden Referenzen/Verweise verwendet, um auf bestimmte Objekte zuzugreifen. Dabei kann es sich um Dateien, Verzeichnisse oder Datenbankeinträge handeln. Bei einer Insecure Direct Object Reference kann der Verweis auf diese Objekte vom Angreifer manipuliert werden, um so Zugriff auf nicht berechtigte Inhalte zu bekommen. Vor allem wenn Applikationen mit sensiblen Daten arbeiten, sind diese Attacken gefährlich. Konkret verwenden Angreifer meist manipulierte IDs oder Pfadangaben, um etwa fremde Datensätze aus der Datenbank auszulesen. [22] 23 Secure .NET Development Das nachfolgende Beispiel soll die Schwachstelle demonstrieren: In einer Webapplikation kann ein angemeldeter Benutzer eine Übersicht über alle seine getätigten Transaktionen abrufen. Dazu wird folgende URL aufgerufen: http://<domain>/Account/TransactionList/3 An der URL lässt sich feststellen, dass im Query String der Wert 3 übergeben wird. In ASP.NET kann ein Default Parameter definiert werden, wodurch nur mehr der Wert angegeben werden muss. Wenn zum Beispiel „id“ als Default Parameter definiert wurde, dann würden die zwei nachfolgende Aufrufe zum selben Ziel führen: http://<domain>/Account/TransactionList/3 http://<domain>/Account/TransactionList?id=3 Um eine Insecure Direct Object Reference Attacke durchzuführen, muss lediglich ein anderer Wert übergeben werden. Wenn man dadurch Zugriff auf den Inhalt eines anderen Benutzers bekommt, so war der Angriff erfolgreich. Beispiel für Aufruf: http://<domain>/Account/TransactionList?id=4 Damit diese Schwachstelle in .NET Webapplikationen verhindert wird, sind folgende Mechanismen möglich: Eindeutig identifizierbare Objekte sollten immer mit einem Globally Unique Identifier (GUID) adressiert werden. Dabei handelt es sich um eine 128 Bit lange Zeichenfolge, wodurch es 2128 (= 340 Sextillionen) Möglichkeiten gibt. [23] Die Wahrscheinlichkeit für eine Kollision ist somit sehr gering. GUIDs werden üblicherweise im Format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX dargestellt, wobei jedes ‘X’ für einen hexadezimalen Wert (0-9 oder A-F) steht. Dadurch würde der Aufruf folgendermaßen aussehen: http://<domain>/Account/TransactionList?id= aa6cd0a0-fd0a-4fdd-8bb5dc155e1f3a59 Zusätzlich sollte auf der Serverseite überprüft werden, ob der aktuelle Benutzer für die angefragte Ressource berechtigt ist. Wenn der Zugriff nicht erlaubt ist, sollte der HTTP Code 403 (Forbidden) zurückgeliefert werden. Um beispielsweise in .NET sicherzustellen, dass eine Ressource nur für Benutzer mit der Admin Rolle sowie für den eigenen Benutzer bereitgestellt wird, kann folgender Code angewendet werden: 1 2 3 if (!User.IsInRole(“admin“) && !User.Identity.GetUserId().Equals(id)) throw new HttpException((int)HttpStatusCode.Unauthorized, „Forbidden"); Listing 11: Berechtigung für Direct Object Reference überprüfen 24 Secure .NET Development Die Variable „id“ enthält die ID für die angeforderte Ressource. In diesem Beispiel (Listing 11) wird hier die ID eines Benutzers angegeben. 3.4. Cross-Site-Request-Forgery (CSRF) Eine Cross-Site-Request-Forgery (CSRF) ist eine weitere Angriffsmöglichkeit auf eine Webapplikation, um Aktionen im Kontext einer anderen Person (Opfer) durchzuführen. Dabei nutzt ein Angreifer die Session seines Opfers zum Senden von manipulierten Anfragen (POST Requests) an den Webserver. Um eine solche Attacke erfolgreich auszuführen, muss also ein angemeldeter Benutzer dazu gebracht werden, die präparierten Request an den Server zu schicken. [24] Dazu stehen folgende Möglichkeiten offen: Cross-Site-Scripting: Wenn eine Webanwendung eine XSS Schwachstelle besitzt, kann der Angreifer ein HTML oder einen JavaScript Code einschleusen, welcher die entsprechenden POST Requests durchführt. Der Code würde bei einer späteren Anfrage im Kontext des aufgerufenen Benutzers ausgeführt werden. Nähere Informationen zu XSS können unter 3.1 nachgelesen werden. URL: Ist eine Webapplikation nicht XSS anfällig, so können die manipulierten Requests auch über eine eigene Webseite bereitgestellt werden. Die Webseite muss nicht einmal Teil der betroffenen Webapplikation sein, sondern kann unter einer anderen Adresse bzw. Domain bereitgestellt werden. Die URL der präparierten Seite wird üblicherweise per E-Mail oder über Sozial Media verteilt. Im Gegensatz zu XSS muss der Angreifer hier das Opfer aktiv dazu bringen, die Webseite aufzurufen. Lokale Schadsoftware: Wenn es möglich ist, eine Schadsoftware auf dem Computersystem des Opfers zu installieren, welches Zugriff auf den Browser hat, kann die Attacke auch durch den installierten Schadcode durchgeführt werden. Dieser muss den Browser dazu bringen, die präparierte Webseite aufzurufen. Das nachfolgende Beispiel soll die Schwachstelle praktisch demonstrieren: Auf einer Webseite können angemeldete Benutzer ihre gesammelten Meilen (Punkte) an andere Benutzer übertragen. Die Meilen werden dann vom eigenen Kontostand abgebucht und beim anderen Benutzer gutgeschrieben. Abbildung 10: CSRF anfällige Webapplikation 25 Secure .NET Development Um eine CSRF durchzuführen, muss ermittelt werden, welche Daten an den Webserver übertragen werden. Dazu einfach den dazugehörigen HTML Code analysieren: 1 2 3 4 5 6 7 <form action="/Donation/Create" method="post"> <label>Amount</label> <input id="Amount" name="Amount" type="text" value="0" /> ... </form> Listing 12:HTML Code der CSRF anfälligen Webseite Wie man in Listing 12 sehen kann, finden man im HTML Code alle notwendigen Informationen: an welche Adresse die Daten gesendet werden: <domain>/Donation/Create welche Daten übertragen werden: Alle input Tags innerhalb des form Tags Da nun alle notwendigen Informationen bekannt sind, kann eine eigene Webseite erstellt werden, welche den POST Request schickt: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <html> <head> <title>Invitation</title> </head> <body style="background-color:#EDECEC"> <image src="invitation.jpg" width="150" height="100" /><br /> <form action="<domain>/Donation/Create" method="post"> <input type="hidden" id="Amount" name="Amount" value="200" /> <input type="hidden" id="Receiver" name="Receiver " value="user2" /> <input type="submit" value="Show details" /> </form> </body> </html> Listing 13: CSRF präparierte Webseite Zeile 8: Es wird eine Einladung als Grafik angezeigt. Dem Opfer soll dadurch vermittelt werden, dass er sich auf einer Webseite befindet, wo er Informationen zu einer Einladung findet. Zeile 10 – 14: Die Daten für die Anfrage werden angegeben. Die Input Tags die den Type hidden besitzen, werden nicht angezeigt. So fällt dem Opfer nicht auf, dass Daten mit seiner Identität versendet werden. Auf der Webseite ist nun der nachfolgende Inhalt (siehe Abbildung 11) zu sehen. Beim Klick auf „Show details“ werden die Daten an den Webserver geschickt, wodurch sich der Benutzer „user2“ 200 Meilen vom aktuellen eingeloggten Benutzer überträgt. 26 Secure .NET Development Abbildung 11: Inhalt der CSRF präparierten Webseite Um dieser Schwachstelle Herr zu werden, muss im form Tag des POST Request ein Token angehängt werden. Zusätzlich muss der idente Token auch in den Cookies abgespeichert werden. Sobald die Daten an den Server gesendet werden, kann serverseitig überprüft werden, ob der Token im Formular und der von den Cookies ident sind. Wenn ja, ist sichergestellt, dass die Daten nicht von einem Dritten geschickt wurden. Um diesen Schutzmechanismus in einer .NET Webapplikation zu implementieren, sind die folgenden Schritte notwendig: [25] View Das Framework besitzt die Hilfsfunktion AntiForgeryToken(), welche am Client einen Token im Formular sowie in den Cookies setzt. Die View muss dazu folgendermaßen erstellt werden: 1 2 3 4 5 6 @using (Html.BeginForm()) { @Html.AntiForgeryToken() ... } Listing 14: Implementieren der AntiForgeryToken() Funktion Durch diese Anweisung wird an den Client folgender HTML Code ausgeliefert: 1 2 3 4 <form action="/Donation/Create" method="post"> <input name="__RequestVerificationToken" type="hidden" value="Jnr7YTsjVA11BrR3FOs5_fwiKKx3GsDongdLUfWDuwWJVvIz18nQ15_EBrsE35b79zNxF-NLFrcu16TYFd7ms5_GOQ-rVvXcFtu9-J--0Q1" /> Listing 15: HTML Code durch die AntiForgeryToken() Funktion Zusätzlich wird folgender Token in den Cookies gesetzt: 27 Secure .NET Development Abbildung 12: Cookie durch die AntiForgeryToken() Funktion Controller Um nun serverseitig zu überprüfen, ob der Token im Formular und der in den Cookies gleich ist, muss bei der entsprechenden Methode das Attribut [ValidateAntiForgeryToken] gesetzt werden. Der Methodenkopf würde folgendermaßen aussehen: 1 2 3 4 5 6 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(CreateDonateViewModel donatemile) { ... } Listing 16: Attribut zum Überprüfen des CSRF Token Mit den beiden Attributen aus Listing 16 wird sichergestellt, dass es sich um einen POST Request handeln muss, bei welchem der Token im Formular und in den Cookies gleich ist. Sollte der Token nicht gesetzt bzw. korrekt sein, so wird eine Exception mit der Nachricht „A required anti-forgery token was not supplied or was invalid” ausgelöst. 3.5. Authentifizierung Mit dem .NET Framework gibt es verschiedene Möglichkeiten, um einen Authentifizierungsprozess durchzuführen. Dabei kümmern sich die mitgelieferten Bibliotheken standardmäßig um viele sicherheitsrelevante Angelegenheiten, wie zum Beispiel das Erstellen von sicheren Cookies am Client. [26] Beim Entwickeln von .NET Anwendungen sollte man immer auf die zur Verfügung stehenden Bibliotheken zurückgreifen und nicht selbst den Authentifizierungsprozess entwickeln, da es sich hierbei um einen sehr kritischen Vorgang handelt. Es müssen eine Reihe an Sicherheitsaspekten erfüllt werden, um resistent gegen Angriffe zu sein. Da die mitgelieferten Bibliotheken auch von vielen anderen Entwicklern eingesetzt werden, sind diese weit verbreitet und haben sich dadurch bewährt. In .NET Anwendungen stehen mehrere unterschiedliche Authentifizierungsmöglichkeiten zur Verfügung. Abhängig vom Speicherort der Zugangsdaten muss die passende Form gewählt werden. Dabei werden folgende Möglichkeiten angeboten: [26] Individual Accounts Diese Authentifizierungsart muss gewählt werden, wenn die Zugangsinformationen in einer eigenen Datenbank gespeichert werden. Ein Benutzer kann sowohl mittels Benutzername und Passwort registriert werden als auch über eine Anmeldung an einem externen Anbieter wie Facebook, Google, 28 Secure .NET Development Microsoft oder Twitter. Bei dieser Auswahl wird ASP.NET Identity (auch als eingesetzt, welche alle notwendigen Methoden und Attribute bereitstellt. ASP Membership) Organizational Accounts Wenn die Benutzerdaten in Azure Active Directory oder Windows Server Active Directory gespeichert sind, so muss die sogenannte Organizational Authentication gewählt werden. Dadurch können bereits bestehende Benutzerdaten für den Zugriff auf eine Webapplikation verwendet werden. Windows Authentication Diese Authentifizierungsform ist für eine Webapplikation im Intranet gedacht. Dabei wird ein SingleSign-On (SSO) vom lokal angemeldeten Windows Benutzer durchgeführt. Da bei Webapplikationen am häufigsten die Individual Accounts verwendet werden, wird deren Funktionalität hier genauer erläutert. Detaillierte Informationen über die anderen Formen können unter http://www.asp.net/aspnet/overview/authentication-and-identity nachgelesen werden. Beim Verwenden von Individual Accounts wird die ASP.NET Forms Authentication eingesetzt, bei welcher der Authentifizierungsvorgang aus drei Komponenten besteht: User Agent (Browser) Forms Authentication Middleware Webapplikation Sobald zum ersten Mal auf eine geschützte Ressource zugegriffen wird, wird der Benutzer auf die Login Seite umgeleitet. Nachdem der Benutzer die Zugangsdaten eingegeben hat, werden diese von der Anwendung überprüft und die User Claims erstellt, welche den Benutzernamen und die Rollen des Benutzers enthalten. Danach werden diese von der Middleware verschlüsselt, kodiert und in ein Ticket umgewandelt und als Cookie zum Client gesendet. Bei den nächsten Zugriffen wird dieses Ticket von der Middleware verifiziert, zurück konvertiert und als HttpContext.User Objekt abgespeichert. Über dieses Objekt kann in der Webapplikation auf den aktuellen Benutzer sowie dessen Rollenmitgliedschaft zugegriffen werden. [27] Der Ablauf wird in der Tabelle 1 veranschaulicht. User Agent (Browser) Forms Authentication Middleware Webapplikation 1. Ressource wird aufgerufen Get /Account/Manage -----------------------> 2. Response Status 401 Da die Ressource eine Authentifizierung verlangt, wird der HTTP Code 401 (Client Unauthorized) zurückgeliefert <------------401----------3. Die Middleware konvertiert den HTTP Code zu 302 (Redirect 29 Secure .NET Development found) und leitet den Client zur Login Seite um <-----------302---------4. Login Seite wird aufgerufen GET /Account/Login? ReturnUrl=/Account/Manage -----------------------> 5. Login Seite wird zurückgeliefert <------------200----------6. Benutzername und Passwort werden zum Server gesendet POST /Account/Login? ReturnUrl=/Account/Manage -----------------------> 7. Die Webapplikation führt folgende Aktionen durch -überprüft die Credentials - führt die Methode IdentityAuthenticationManager.SignIn aus - leitet den Client auf die ReturnUrl um <------------301----------8. Die Middleware konvertiert die User Claims in einen Token und setzt diesen als Cookie beim Client <-----------302---------9. Ressource erneut anfordern, jedoch mit gesetzten Token in den Cookies -----------------------> 10. Die Middleware überprüft und konvertiert den Token zurück. -----------------------> Webapplikation erkennt, dass Benutzer authentifiziert ist und liefert daher die Ressource zurück. <------------200----------Tabelle 1: Ablauf einer Forms Authentication [27] 30 Secure .NET Development Der Vorgang für die Authentifizierung mit einem externen Provider wie Facebook, Google, Microsoft oder Twitter ist ein klein wenig anders als in Tabelle 1 gezeigt [27]. Der hierfür notwendige Authentifizierungsprozess kann unter http://blogs.msdn.com/b/webdev/archive/2013/07/03/understandingowin-forms-authentication-in-mvc-5.aspx nachgelesen werden. Um den Authentifizierungsprozess aus der Tabelle 1 zu implementieren, sind nur wenige Schritte notwendig: Eine geschützte Ressource muss mit dem Attribut Authorize versehen werden. Dieses Attribut kann sowohl auf eine Methode als auch auf einen Controller angewendet werden. Wenn nur eine bestimmte Gruppe auf die Ressource zugreifen darf, so kann auch der Parameter Roles angegeben werden (siehe Listing 17) 1 2 3 4 5 [Authorize(Roles = „admin“)] public ActionResult ResetPassword(string id, MessageStates? message) { ... } Listing 17: Authorize Attribut Nachdem der Benutzer die Zugangsdaten (Benutzername und Passwort) angegeben hat, müssen diese überprüft werden. Sind diese korrekt, so werden die User Claims erstellt und der Benutzer angemeldet. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var user = UserManager.Find(model.UserName, model.Password); if (user != null) { var identity = UserManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Invalid username or password."); } Listing 18: Implementierung der Forms Authentication In Listing 18 werden folgende Aktionen durchgeführt: Zeile 1 - 2: Es wird überprüft, ob die Kombination von Benutzername und Passwort in der Datenbank vorhanden ist. Damit das Objekt UserManager einen Zugriff auf die Datenbank hat, muss es zuvor mit dem Entity Framework Kontext initialisiert werden. Zeile 4 – 5: Da der Benutzer gültige Zugangsdaten angegeben hat, werden die User Claims abgefragt. Diese bestehen aus dem Benutzernamen und den dazugehörigen Rollen/Gruppen. Zeile 7 – 8: Die User Claims werden an die Middleware übergeben. Zusätzlich wird mitgeteilt, ob der Benutzer die Checkbox „Angemeldet bleiben“ aktiviert hat. 31 Secure .NET Development Zeile 10: Der Benutzer wird zur gewünschten Ressource geleitet. Zeile 14: Wenn der Benutzer ungültige Zugangsdaten eingegeben hat, wird eine entsprechende Fehlermeldung zurückgeliefert. 3.6. ASP.NET Web API Bei ASP.NET Web API handelt es sich um ein typisches Webservice. Ein Webservice ist eine Softwareanwendung, welche für die direkte Maschine-zu-Maschine (M2M) Kommunikation verwendet wird. Dabei wird der Dienst von einem Webserver betrieben. Da der Zugriff über standardisierte Protokolle wie HTTP und XML gesteuert wird, können solche Dienste für die Kommunikation in heterogenen Netzwerken eingesetzt werden. [28] Häufig werden Webservices als Schnittstelle zwischen den Clients und einer Datenbank verwendet, da hiermit ein Zugriff von unterschiedlichen Geräten auf eine Datenbank möglich wird. Webservices, vor allem solche, die in öffentlichen Netzen angeboten werden, sind einer Vielzahl von Angriffen ausgesetzt. Insbesondere Angriffe, die die Verfügbarkeit von Systemen vollständig eliminieren können, die sogenannten Denial-of-Service (DOS) Attacken, stellen eine große Gefahr dar. [29] Aber auch durch unbefugte Zugriffe auf Webservices, welche als Schnittstellen zu sensiblen Daten fungieren, können schwerwiegende Schäden entstehen. Daher müssen Maßnahmen wie Authentifizierung, Validierung und DOS Abwehrmechanismen eingesetzt werden. Authentifizierung Da .NET Webservices (Web API) im Aufbau sehr viele Gemeinsamkeiten mit .NET Webapplikationen haben, kann auch der gleiche Authentifizierungsprozess verwendet werden. Daher können die Informationen unter 3.5 auch für Web APIs angewendet werden. Validierung Damit ein Webservice gegen manipulierte Eingabedaten geschützt ist, um beispielsweise gegen SQL Injection resistent zu sein, können die gleichen Maßnahmen wie bei den Webapplikationen verwendet werden: Um sich dagegen zu schützen, müssen sichere Datenbankzugriff verwendet werden (siehe 3.2.2). Das Einschleusen von Script Code kann durch das Attribut [ValidateInput(true)] verhindert werden (siehe 3.1). DOS Protection Bei einem verteilten DoS Angriff werden die Webserver von einer großen Anzahl von Rechnern mit vielen Anfragen überflutet, wodurch die Server überlastet werden und dadurch Anfragen nicht oder nur begrenzt beantworten können. Um dies zu vermeiden, könnte eine Firewall nur autorisierte IP Adressen durchlassen, um die Anzahl der Anfragen zu minimieren. [29] Das funktioniert aber nicht immer, da Webservices sehr oft für die Öffentlichkeit bereitgestellt werden. Daher müssen die angebotenen Dienste so entwickelt werden, dass keine Überlast produziert werden kann. ASP.NET Web APIs können in Kombination mit Open Data Protocol (OData) als REST-basierte Datendienste fungieren. Dadurch können Ressourcen, welche über URIs (Uniform Resource Identifiers) identifiziert werden und in einem Datenmodell definiert sind, mittels HTTP-Nachrichten veröffentlicht und 32 Secure .NET Development bearbeitet werden. [30] Dadurch ergibt sich der Vorteil, dass nicht für jeden Datenbankzugriff eine eigene Methode geschrieben werden muss (GetAllProducts(), GetProductsById (…), GetProductsByName (…), …). Um beispielsweise alle Produkte sortiert abzurufen, würde folgender Aufruf genügen: http://<domain>/webservice.svc/products?$orderby=name Im Webservice muss keine eigene Methode implementiert werden, da OData die übergebene Anweisung in eine Datenbankabfrage konvertiert und das Ergebnis als JSON oder XML zurücksendet. Das Gefährliche an dieser Art ist, dass Angreifer einen Webserver mit einer Reihe von komplexen Anweisungen schnell zu einer hohen Auslastung bringen können. Würde es zum Beispiel 1 Million Produkte geben und die vorherige Anfrage würde alle 500 Millisekunden gesendet werden, so würde der Server schnell an seine Grenzen stoßen. Um dies zu vermeiden, können folgende Mechanismen implementiert werden: [31] Anzahl der Datensätze einschränken Damit bei großen Datenmengen nicht alle Daten auf einmal an die Client übertragen werden, sollte man Pagging verwenden, um die Daten stückweise auszuliefern. Mit dem nachfolgenden Attribut würden maximal 100 Datensätze zurückgeliefert werden. 1 2 [Queryable(PageSize = 100)] public IQueryable<Product> Get() Listing 19: OData - Anzahl der Datensätze einschränken Nur bestimmte Operationen zulassen Damit beispielsweise keine OrderBy Anweisungen gesendet werden können, sondern nur zugelassene Operationen, müssen diese explizit erlaubt werden. 1 2 [Queryable(AllowedQueryOptions = AllowedQueryOptions.Filter | AllowedQueryOptions.Top)] public IQueryable<Product> Get() Listing 20: OData - Operationen einschränken Es gibt noch eine Menge weitere Einschränkungen wie zum Beispiel das Zulassen von bestimmte Arithmetische Optionen. Diese können unter http://blogs.msdn.com/b/webdev/archive/2013/02/06/protectyour-queryable-api-with-validation-feature-in-asp-net-web-api-odata.aspx abgerufen werden. 33 Secure .NET Development 4. Windows Communication Foundation (WCF) Seit 2006 liefert Microsoft mit dem .NET Framework 3.0 die Windows Communication Foundation (WCF) mit, wodurch es möglich wurde, verteilte Applikationen auf Basis von SOA (Service-oriented Architecture) zu schreiben. Zuvor gab es dafür zwar auch schon Technologien wie .NET Remoting, Message Queuing (MSMQ) oder Enterprise Services, jedoch konnten diese immer nur für bestimmte Anforderungen genutzt werden. Daher vereinigte Microsoft mit WCF alle diese Technologien zu einem Guss, um ein zentrales Framework für viele Situationen bereitzustellen. [32, pp. 327, 328] In der Tabelle 2 werden alle zusammengefassten Technologien von WCF gezeigt. Technologie ASMX Anforderung Interoperable Web Services Binary .NET .NET Communication Distributed Transactions, etc. .NET Remoting Enterprise Services WSE System. Messaging System. NET X WCF X X X X Support für WS* Specifications X X Queued Messaging X X RESTful Communication X x x Tabelle 2: Technologien von WCF [33, p. 7] 4.1. Endpoints Um ein WCF Service zu veröffentlichen, muss ein sogenannter Endpoint eingerichtet werden. Dieser besteht aus den drei Komponenten Address, Contract und Binding. Auch der Client benötigt diese Informationen, um mit dem Service kommunizieren zu können. [32, p. 340] Address – Wo finde ich den Dienst? Eine Adresse besteht aus dem Transport Protokoll, dem Maschinennamen, einem Port und einem Pfad. Die Syntax einer Adresse lautet daher: Protokoll://<Maschinenname>[:port]/>Pfad zum Service> 34 Secure .NET Development WCF unterstützt dabei mehrere Protokolle, welche je nach Anforderung eingesetzt werden können: [32, pp. 340, 341] HTTP: das häufigste verwendete Protokoll, um auf ein WCF Service zuzugreifen. Ein Vorteil ist, dass durch einen Browser auf das Service zugegriffen werden kann. Adresse: http://<domain>/<Pfad zum Service> Named Pipes: Dieses Protokoll wird für Inter-Prozess oder In-Prozess Kommunikationen verwendet. Adresse: net.pipe://example.com/Products/GetAllProducts TCP: ähnlich wie das HTTP Protokoll, kann jedoch nicht über einen Webbrowser aufgerufen werden. Adresse: net.tcp://example.com/Products/GetAllProducts MSMQ: Message Queues haben den Vorteil, dass Daten kurzzeitig zwischengespeichert werden können. Somit kann ein Server für kurze Zeit offline sein, da er die Daten nachträglich aus der Queue empfängt. Bei diesem Protokoll gibt es keine Portangabe. Adresse: net.msmq://example.com/Products/GetAllProducts Contract – Was wird zwischen dem Client und dem Service ausgetauscht? [34] Contracts sind Interfaces und Datenstrukturen, die angeben, welche Operationen und Daten ein Service anbietet. Es gibt drei Typen von Contracts: Service Contract: beschreibt eine Reihe zusammenhängender Operationen in einem gemeinsamen Interface. Um eine Klasse als Service anzubieten, muss das Attribut [ServiceContract] gesetzt werden. Zusätzlich muss jede Methode, welche veröffentlich werden soll, mit dem Attribut [OperationContract] gekennzeichnet werden. (siehe Listing 21) Data Contract: Damit komplexe bzw. eigene Datentypen serialisiert werden können, muss bei der entsprechenden Klasse und den gewünschten Properties das Attribut [DataContract] gesetzt werden. Message Contract: Um mehr Kontrolle über die von WCF generierten SOAP Nachrichten zu bekommen, können MessageContracts verwendet werden. Dazu muss über die Klasse das Attribut [MessageContract] gesetzt werden. Die gewünschten Properties könnten dann entweder mit dem Attribut [MessageBody] oder [MessageHeader] gekennzeichnet werden. 1 2 3 4 5 6 7 8 9 [ServiceContract] public interface IRandomService { [OperationContract] int GetRandomNumber(); [OperationContract] int GetRandomNumberInRange(int min, int max); } Listing 21: Service Contract Binding – Wie kommuniziere ich mit dem Dienst? 35 Secure .NET Development Mit den Bindings wird festgelegt, wie ein Dienst mit der Außenwelt kommuniziert. Dabei werden Aspekte wie die verwendete Kommunikationstechnik (HTTP, TCP, …), die Kodierung (Binär, Text, XML, …), die eingesetzte Verschlüsselungstechnik und vieles mehr beschrieben. Da es sehr viele Konfigurationsparameter gibt, können vom Framework bereitgestellte Bindings wie BasicHttpBinding, NetTcpBinding, usw. verwendet werden. [3, p. 104] Details über alle Bindings können unter http://msdn.microsoft.com/en-us/library/ms730879(v=vs.110).aspx abgerufen werden. Die Parameter Adress und Binding können sowohl im Quellcode also auch in einer Konfigurationsdatei angegeben werden. Beim Verwenden einer Konfigurationsdatei ergibt sich der Vorteil, dass bei Änderungen nicht neu kompiliert werden muss. [3, p. 104] Um einen Endpoint für das Service und den Client zu erstellen, ist folgender Konfigurationseintrag notwendig: Server 1 2 3 4 5 6 7 8 9 10 11 <system.serviceModel> <services> <service name="WcfService.RandomService"> <endpoint address="net.tcp://localhost:8732/Random" binding="netTcpBinding" contract="WcfService.IRandomService"/> <endpoint address="net.tcp://localhost:8733/mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </service> </services> </system.serviceModel> Listing 22: WCF Endpoint (Service) In Listing 22 wird folgende Konfiguration festgelegt: Zeile 3: Die Klasse RandomService wird als Service veröffentlich. In dieser Klasse wurden die Methoden des Service Contracts aus Listing 21 implementiert. Zeile 4 – 5: Mit dem Endpoint wird festgelegt, dass die Kommunikation über TCP läuft. Die Konsumenten könnten dabei alle Operationen nutzen, welche im Contract WcfService.IRandomService definiert wurden. Zusätzlich wird noch die Adresse für den Dienst angegeben. Zeile 7 – 8: Dieser Endpoint ist für den Austausch von Metadaten notwendig. Der Endpoint ist nicht zwingend für die Funktionalität notwendig, erleichtert aber die Entwicklung von WCF Diensten in Visual Studio enorm. Client 1 2 3 4 5 6 <system.serviceModel> <client> <endpoint address="net.tcp://localhost:8732/Random" binding="netTcpBinding" contract="RandomService.IRandomService"/> </client> </system.serviceModel> Listing 23: WCF Endpoint (Client) 36 Secure .NET Development In Listing 23 wird folgende Konfiguration festgelegt: Zeile 3 – 4: Um eine Verbindung mit dem WCF Service aus Listing 22 aufbauen zu können, muss am Client der gleiche Endpoint angegeben werden. Der große Vorteil von WCF ist nun, dass man zum Beispiel in nur einem Schritt die Übertragungstechnik ändern kann, ohne den Code anpassen zu müssen. Soll die Kommunikation auf HTTP umgestellt werden, so muss der Parameter netTcpBinding auf basicHttpBinding sowie das Protokoll in der Adresse auf http:// geändert werden. 4.2. Sicherheitsmechanismen Einer der wichtigsten Punkte bei verteilten Anwendungen ist die Sicherstellung einer sicheren Kommunikation. Gerade bei der Übertragung von sensiblen Daten über öffentliche Netze müssen Aspekte wie Vertraulichkeit, Integrität und Authentizität gewährleistet werden. Bei WCF unterscheidet man dabei zwischen der Transportsicherheit und der Nachrichtensicherheit. Bei der Transportsicherheit wird der Übertragungskanal entweder mit SSL (Secure Socket Layer) oder SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) verschlüsselt. Da SSL durch den Einsatz im World Wide Web sowie SPNEGO für Integrated Windows Authentication schon lange im Einsatz sind, haben sich diese Technologien bereits bewährt. Bei der Nachrichtensicherheit wird die Nachricht selbst verschlüsselt und signiert. [3, pp. 105, 106] Dazu bietet WCF die verschiedenen WS-* Klassen wie WS-Security, WS-Trust und WS-SecureConversation an. [33, p. 10] Es kann auch ein Mix von Transportsicherheit und Nachrichtensicherheit durchgeführt werden. So wird zum Beispiel die Nachricht verschlüsselt, signiert und anschließend über einen SSL Port übertragen, ohne nochmals verschlüsselt zu werden. Die Verschlüsselung mittels Transportsicherheit wird im Gegensatz zur Nachrichtensicherheit Stream-basiert durchgeführt. Daher sollte aus Performance Gründen die Chiffrierung mittels Transportsicherheit realisiert werden. [3, p. 106] Da die vom WCF bereitgestellten Bindings zum Teil standardmäßig keine Sicherheitsparameter setzen, muss dies durch weitere Konfigurationsschritte manuell durchgeführt werden. Beim Verwenden von basicHttpBinding ohne weitere Einstellungen werden keine Sicherheitsmechanismen verwendet. In der Abbildung 13 wurde die Kommunikation mit einem Sniffer abgehört, um die ausgetauschten Daten auszulesen. Werden nun beispielsweise Kreditkarteninformationen ausgetauscht, so wäre das eine fatale Sicherheitslücke. Um dies zu beheben, kann die Flexibilität von WCF genutzt werden: Es muss lediglich die Konfiguration der Bindings erweitert werden und diese im Endpoint mit dem Parameter bindingConfiguration verknüpft werden. (siehe Listing 24) 37 Secure .NET Development Abbildung 13: WCF Kommunikation im Klartext 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <system.serviceModel> <services> <service name="WcfService.RandomService"> <endpoint address="https://10.0.0.29:8735/Math" bindingConfiguration="customBinding" binding="basicHttpBinding" contract="WcfService.IRandomService" /> </service> </services> <bindings> <basicHttpBinding> <binding name="customBinding"> <security mode="Transport" /> </binding> </basicHttpBinding> </bindings> </system.serviceModel> Listing 24: WCF mit Transportsicherheit Wie in den Zeile 9 – 15 von Listing 24 zu sehen ist, wurde eine benutzerdefinierte Binding erstellt. In dieser wurden die Parameter für eine Transportsicherheit gesetzt. Dieses Binding ET1(ur)-14(de)4( )25(e)-9s TJE6ETBdadefit 38 Secure .NET Development 4.3. WCF vs. ASP.NET Web API WCF Dienste können als Webservice, Stand-Alone Applikation oder Windows Service betrieben werden. Nun bietet das .NET Framework allerdings auch die ASP.NET Web API (siehe 3.6) zum Entwickeln von Webservices an. Welche Technologie sollte nun zum Entwickeln eines Webservices verwendet werden? WCF gilt als sehr mächtiges Framework, da durch die zahlreichen Konfigurationsmöglichkeiten sehr viele Anforderungen abgedeckt werden können. Dadurch ist es aber auch komplexer als ein einfaches ASP.NET Webservice. Und genau hier liegt auch der größte Unterschied: ASP.NET Webservices sind im Gegensatz zu WCF klein, leichtgewichtig und einfach in Betrieb zu nehmen. [37] Um besser entscheiden zu können, welche Technologie am besten eingesetzt werden soll, werden in der Tabelle 3 die Features gegenübergestellt: WCF Mehrere Übertragungsprotokolle (HTTP, TCP, UDP) Mehrere Kodierungsmöglichkeiten (Text, MTOM und Binär) Unterstützt WS-* Standards wie Reliable Messaging, Transactions oder Message Security Unterstützt Request-Reply, One Way und Duplex message exchange Mit .NET Framework mitgeliefert ASP.NET Web API Nur HTTP als Übertragungsprotokoll Daten werden üblicherweise mittels XML oder JSON serialisiert Es werden Basis Protokolle und Formate wie HTTP, SSL, JSON und XML verwendet. Es gibt keine Unterstützung für höhere Protokolle wie Reliable Messaging oder Transactions HTTP basiert auf Request/Response Ebenfalls im .NET Framework enthalten, ist jedoch Open Source Tabelle 3: WCF Webservice vs. ASP.NET Web API [37] ASP.NET Web API wird sehr stark weiterentwickelt, da leichtgewichtige Dienste durch die starke Verbreitung von mobilen Geräten immer mehr an Bedeutung gewinnen. Daher sollte man bei neuen Projekten die ASP.NET Web API bevorzugen, wenn diese alle Anforderungen erfüllen kann. 39 Secure .NET Development 5. Kryptographie In diesem Kapitel geht es um kryptografische Konzepte in .NET. Kryptographie ist die Lehre von der Verund Entschlüsselung. Dadurch können vertrauliche Daten über unsichere Netze wie beispielsweise das Internet übertragen werden, ohne dass diese von unberechtigten Personen gelesen werden können. Um dies zu erreichen, werden Verschlüsselungsalgorithmen oder Chiffriercodes auf die Daten angewendet, welche aus mathematischen Funktionen zur Ver- und Entschlüsselung bestehen. Die Sicherheit der verschlüsselten Daten ist dabei von der Stärke des Verschlüsselungsalgorithmus und der Geheimhaltung sowie der Länge des Schlüssels abhängig. [38, p. 3] In der modernen Kryptographie werden folgende Ziele verfolgt, um Informationen zu schützen: [39, pp. 14] Vertraulichkeit: Nur berechtigte Personen dürfen Zugriff auf den Inhalt von Nachrichten bekommen. Integrität: Es muss für den Empfänger nachprüfbar sein, dass er die Nachricht unversehrt erhalten hat. Authentizität: Die Identität des Absenders einer Nachricht soll für den Empfänger nachprüfbar sein. Verbindlichkeit: Ein Absender einer Nachricht soll seine Urheberschaft später nicht verleugnen können. 5.1. Symmetrische Verfahren Bei symmetrischen Verschlüsselungen wird für die Ver- und Entschlüsselung ein einziger Schlüssel benötigt, d.h. sowohl der Absender als auch der Empfänger müssen denselben Schlüssel besitzen. Dieses Verschlüsselungssystem ist sehr schnell. Der Nachteil ist jedoch der Schlüsselaustausch: Bekommt ein Angreifer bei der Schlüsselverteilung Zugriff auf den Schlüssel, so kann er alle Daten entschlüsseln. Daher sollte die symmetrische Verschlüsselung nur eingesetzt werden, wenn eine der folgenden Gegebenheiten zutrifft: [38, p. 3] Es werden nur lokale Daten verschlüsselt, welche nicht übertragen werden. Es wird ein sicheres Protokoll für den Schlüsselaustausch verwendet, wie z.B. Diffie-Hellman. Die symmetrische Verschlüsselung wird in Kombination mit einer asymmetrischen Verschlüsselung durchgeführt. Für symmetrische Verschlüsselungen stehen bekannte Algorithmen wie Advanced Encryption Standard (AES) oder auch Rijndael-Algorithmus: Schlüssellänge 128, 192 oder 256 Bit Data Encryption Standard (DES): Schlüssellänge 56 Bit Tripple-DES: Schlüssellänge 112 Bit zur Verfügung. In dem nachfolgenden Beispiel wird der AES als Verschlüsselungsalgorithmus verwendet. Es wird eine Client-Server Anwendung erstellt, wo Nachrichten vom Client verschlüsselt an den Server gesendet werden. Bei Bedarf können auch andere Algorithmen eingesetzt werden. Beachten Sie jedoch, dass Schlüssel mit weniger als 100 Bit bei symmetrischen Verfahren als nicht sicher eingestuft werden. 40 Secure .NET Development Server 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 static void Main(string[] args) { try { TcpListener tcpListener = new TcpListener (IPAddress.Parse ("127.0.0.1"), 8001); tcpListener.Start(); Socket socket = tcpListener.AcceptSocket(); NetworkStream nStream = new NetworkStream(socket); StreamReader reader = new StreamReader(nStream); byte[] iv = Convert.FromBase64String(reader.ReadLine()); byte[] key = Convert.FromBase64String(reader.ReadLine()); while (true) { string msg = streamreader.ReadLine(); Console.WriteLine("Received: " + DecryptData(msg, iv, key)); } reader.Close(); nStream.Close(); socket.Close(); tcpListener.Stop(); } catch (Exception e) { Console.WriteLine("Error..... " + e.StackTrace); } } public static string DecryptData(string input, byte[] iv, byte[] key) { MemoryStream tmpStream = new MemoryStream(); RijndaelManaged aes = new RijndaelManaged(); CryptoStream cs = new CryptoStream(tmpStream, aes.CreateDecryptor(key, iv), CryptoStreamMode.Write); byte[] data = Convert.FromBase64String(input); cs.Write(data, 0, data.Length); cs.FlushFinalBlock(); return Convert.ToBase64String(tmpStream.ToArray()); } Listing 25: TCP Server für AES Kommunikation Im Listing 25 werden folgende Aktionen durchgeführt: 41 Secure .NET Development Zeile 5 - 7: Der TCP Port 8001 wird geöffnet. Zeile 9: Es wird auf einen Verbindungsaufbau eines Clients gewartet. Sobald eine Verbindung aufgebaut wird, wird ein Socket erzeugt. Zeile 11 – 12: Es wird ein Übertragungskanal erstellt, über welchen die gesendet Daten vom Client gelesen werden. Zeile 14 – 15: Der Server erwartet in den ersten beiden Nachrichten den Initialisierungsvektor (IV) und den Schlüssel, die für die nachfolgende Entschlüsselung verwendet werden sollen. Zeile 17 – 21: Die gesendeten Daten werden eingelesen und mit dem zuvor erhaltenen IV und Schlüssel entschlüsselt und ausgegeben. Zeile 23 – 26: Der Übertragungskanal und die Verbindung werden geschlossen. Zeile 36: Es wird eine Instanz vom Objekt MemoryStream erstellt, welche zum Zwischenspeichern der entschlüsselten Daten benötigt wird. Zeile 37: Es wird eine Instanz vom Objekt RijndaelManaged erstellt, welche zum Entschlüsseln der Daten benötigt wird. Zeile 39 – 40: Es wird eine Instanz vom Objekt CryptoStream erstellt, durch welche die Daten entschlüsselt werden. Als Parameter müssen der Zielort und der Entschlüsselungsalgorithmus angegeben werden. Zeile 42 – 44: Die Daten werden in ein Byte Array umgewandelt und durch den erstellten CryptoStream geschickt. Erst durch die Methode Flush() werden die Daten dann entschlüsselt in den MemoryStream geschrieben. Zeile 46: Nun können die entschlüsselten Daten aus dem MemoryStream ausgelesen und zurückgeliefert werden. Da die Daten als Byte Array abgespeichert wurden, müssen diese zuvor noch in ein String Element konvertiert werden. Client 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 static void Main(string[] args) { try { TcpClient tcpclnt = new TcpClient(); tcpclnt.Connect("127.0.0.1", 8001); NetworkStream nStream = tcpclnt.GetStream(); StreamWriter writer = new StreamWriter(nStream); RijndaelManaged aes = new RijndaelManaged(); byte[] iv = aes.IV; byte[] key = aes.Key; writer.WriteLine(Convert.ToBase64String(iv)); writer.WriteLine(Convert.ToBase64String(key)); writer.Flush(); while (true) { Console.Write("Enter the string to be transmitted : "); writer.WriteLine(EncryptData(Console.ReadLine(), iv, key)); writer.Flush(); } 42 Secure .NET Development 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 reader.Close(); nStream.Close(); socket.Close(); tcpclnt.Close(); } catch (Exception e) { Console.WriteLine("Error..... " + e.StackTrace); } } public static string EncryptData(string input, byte[] iv, byte[] key) { MemoryStream tmpStream = new MemoryStream(); RijndaelManaged aes = new RijndaelManaged(); CryptoStream cs = new CryptoStream(tmpStream, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write); byte [] data = Convert.FromBase64String(input); cs.Write(data, 0, data.Length); cs.FlushFinalBlock(); return Convert.ToBase64String(tmpStream.ToArray()); } Listing 26: TCP Client für AES Kommunikation Im Listing 26 werden folgende Aktionen durchgeführt: Zeile 5 - 3: Es wird eine Verbindung zum Server aufgebaut. Zeile 8 – 9: Es wird ein Übertragungskanal erzeugt, über welchen die Daten zum Server gesendet werden. Zeile 11 – 13: Der Initialisierungsvektor (IV) und der Schlüssel werden erstellt. Diese werden für die nachfolgende Verschlüsselung verwendet. Um zufällige Werte zu erhalten, werden diese mit dem RijndaelManaged Objekt erstellt. Zeile 15 – 17: Die generierten Werte werden an den Server gesendet. Erst durch die Methode Flush() werden die Daten tatsächlich übertragen. Zeile 19 – 24: Die eingegebenen Daten werden verschlüsselt und an den Server gesendet. Zeile 26 – 29: Der Übertragungskanal und die Verbindung werden geschlossen. Zeile 39: Es wird eine Instanz vom Objekt MemoryStream erstellt, welche zum Zwischenspeichern der verschlüsselten Daten benötigt wird. Zeile 40: Es wird eine Instanz vom Objekt RijndaelManaged erstellt, welche zum Verschlüsseln der Daten benötigt wird. Zeile 42 – 43: Es wird eine Instanz vom Objekt CryptoStream erstellt, durch welche die Daten verschlüsselt werden. Als Parameter müssen der Zielort und der Entschlüsselungsalgorithmus angegeben werden. Zeile 45 – 47: Die Daten werden in ein Byte Array umgewandelt und durch den erstellten CryptoStream geschickt. 43 Secure .NET Development Zeile 49: Nun können die verschlüsselten Daten aus dem MemoryStream ausgelesen und zurückgeliefert werden. Da die Daten als Byte Array abgespeichert wurden, müssen diese zuvor noch in ein String Element konvertiert werden. Die Nachrichten werden zwar verschlüsselt vom Client zum Server gesendet, jedoch wurde zuvor der Schlüssel in Klartext ausgetauscht. Konnte ein Angreifer beispielsweise durch Sniffen den Schlüssel und den Initialisierungsvektor abgreifen (siehe Abbildung 14), so könnte er alle übertragenen Daten entschlüsseln. Abbildung 14: Schlüsselaustausch abhören In der Abbildung 14 wird in der Client Applikation der generierte Schlüsselt ausgelesen. Zeitgleich wurde das Sniffing Programm Wireshark gestartet, um alle Netzwerkaktivitäten abzuhören. Wie man erkennen kann, konnte der generierte Schlüssel unverfälscht ermittelt werden. Um dies zu vermeiden, kann beispielsweise das Diffie-Hellman Protokoll eingesetzt werden. 5.1.1. Diffie-Helman Protokoll Beim Diffie-Helman Protokoll handelt es sich um den ersten Verschlüsselungsalgorithmus, in dem diskrete Logarithmen in einem endlichen Feld verwendet werden. Es wurde 1976 von Martin Hellman und Whitfield Diffie erfunden. [38, p. 70] Das Ziel dieses Algorithmus ist ein sicherer Schlüsselaustausch über ein unsicheres Kommunikationsmedium. Um dies zu erreichen, müssen folgende Schritte durchgeführt werden. [39, p. 29] Beide Teilnehmer generieren eine Primzahl p und eine natürliche Zahl g. Da diese Zahlen nicht geheim bleiben müssen, können sie über einen unsicheren Kanal ausgetauscht werden. 44 Secure .NET Development Beide Teilnehmer erzeugen jeweils geheim zu haltende Zufallszahlen a bzw. b, welche nicht übertragen werden. Nachdem p und g ausgetauscht wurden, berechnen die Teilnehmer A = ga mod p bzw. B = gb mod p. Danach wird A und B ausgetauscht. Nun können beide Teilnehmer den gemeinsamen Schlüssel berechnen: K = Ba mod p bzw. K = Ab mod p Um dieses Verfahren in einer .NET Anwendung zu implementieren, können mitgelieferte Bibliotheken verwendet werden. Dazu wird das Beispiel aus Listing 25 und Listing 26 folgendermaßen erweitert: Client 1 2 3 4 5 6 7 8 9 10 11 ECDiffieHellmanCng dh = new ECDiffieHellmanCng(); dh.HashAlgorithm = CngAlgorithm.Sha256; byte[] publicKey = dh.PublicKey.ToByteArray(); writer.WriteLine(Convert.ToBase64String(publicKey)); writer.Flush(); byte[] srvPublicKey = Convert.FromBase64String (reader.ReadLine()); byte[] key = dh.DeriveKeyMaterial(CngKey.Import(srvPublicKey, CngKeyBlobFormat.EccPublicBlob)); Listing 27: Diffie-Hellman Implementierung (Client) Server 1 2 3 4 5 6 7 8 9 10 11 byte[] clientPublicKey = Convert.FromBase64String(reader.ReadLine()); ECDiffieHellmanCng dh = new ECDiffieHellmanCng(); dh.HashAlgorithm = CngAlgorithm.Sha256; byte[] publicKey = dh.PublicKey.ToByteArray(); writer.WriteLine(Convert.ToBase64String(publicKey)); writer.Flush(); byte[] key = dh.DeriveKeyMaterial(CngKey.Import(clientPublicKey, CngKeyBlobFormat.EccPublicBlob)); Listing 28: Diffie-Hellman Implementierung (Server) Im Beispiel von Listing 27 und Listing 28 wird ein Diffie-Hellman Schlüsselaustausch auf Basis von elliptischen Kurven durchgeführt. Dabei werden folgende Schritte abgearbeitet: [40] Client und Server generieren jeweils ein Schlüsselpaar für den Diffie-Hellman Schlüsselaustausch. Client und Server konfigurieren jeweils dieselben Parameter der Key Derivation Function (KDF). Eine KDF ist ein deterministischer Algorithmus, um einen Schlüssel aus einem geheimen Wert abzuleiten. Client und Server tauschen den öffentlichen Schlüssel aus. 45 Secure .NET Development Client und Server nutzen den öffentlichen Schlüssel des jeweils anderen für die Generierung des gemeinsamen Schlüssels. 5.2. Asymmetrische Verfahren Bei asymmetrischen Systemen werden zur Ver- und Entschlüsselung unterschiedliche Schlüssel verwendet, die mathematisch miteinander verbunden sind. Dadurch vereinfacht sich das Problem des Schlüsselaustauschs. Nur der Dechiffrierschlüssel muss geheim gehalten werden, der Chiffrierschlüssel kann dagegen öffentlich bekannt sein. Diese Verschlüsselungsart wird auch als Public-Key Verfahren bezeichnet. [3, p. 58] Die Verschlüsselung ist jedoch aufwendiger und daher langsamer, da bei asymmetrischen Verfahren längere Schlüssel (mindestens 2048 Bits) als bei symmetrischen Verfahren (mindestens 128 Bits) verwendet werden und die mathematische Generierung eines Schlüsselpärchens zusätzliche Rechenleistung in Anspruch nimmt. Aus diesem Grund werden häufig hybride Systeme eingesetzt: [41] Die Verschlüsselung der eigentlichen Daten erfolgt symmetrisch mithilfe eines Session Schlüssels. Dieser Schlüssel wird für jede Übertragung generiert, asymmetrisch verschlüsselt und an die eigentliche Nachricht angehängt. So erhält man die Vorteile beider Systeme: Geschwindigkeit und Sicherheit. Das erste praktisch eingesetzte asymmetrische kryptographische Verfahren war der 1977 entwickelte RSA. Der Name ist eine Ableitung von den Erfindern: Ronald Rivest, Adi Shamir und Leonard Adleman. Der RSA ist inzwischen zum de-facto-Standard für die Public-Key Verschlüsselung geworden und ist somit das bekannteste und verbreitetste asymmetrische Verfahren. Die Sicherheit des RSA Algorithmus basiert auf der Faktorisierungsannahme: Die Zerlegung einer großen Zahl in ihre Primfaktoren ist sehr aufwändig, während das Erzeugen einer Zahl durch Multiplikation von Primzahlen recht einfach ist. [42, pp. 84, 85] Der RSA kann zusätzlich zur Verschlüsselung auch für Digitale Signaturen verwendet werden. Dadurch können die Integrität, Authentizität und Verbindlichkeit gewährleistet werden. 5.2.1. Verschlüsselung Um asymmetrische Verschlüsselungen in .NET Anwendungen zu implementieren, kann die Klasse RSACryptoServiceProivder vom Namespace System.Security.Cryptography verwendet werden. Im nachfolgenden Beispiel wird vom Server ein öffentlicher Schlüssel an den Client übertragen. Alle darauffolgenden Daten werden vom Client mit dem öffentlichen Schlüssel verschlüsselt und mit dem privaten Schlüssel entschlüsselt. Die Vorgänge für die TCP Verbindung können aus dem Beispiel von Listing 25 und Listing 26 entnommen werden. Server 1 2 3 4 5 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); writer.WriteLine(Convert.ToBase64String(rsa.ExportCspBlob(false))); writer.Flush(); 46 Secure .NET Development 6 7 8 9 10 11 12 13 14 while (true) { string secureContent = streamreader.ReadLine(); byte[] decryptBytes = rsa.Decrypt (Convert.FromBase64String( secureContent), false); Console.WriteLine("Received: " + Encoding.UTF8.GetString ( decryptBytes)); } Listing 29: RSA Verschlüsselung (Server) In Listing 29 werden folgende Aktionen durchgeführt: Zeile 1: Es wird eine Instanz der Klasse gewünschten Schlüssellänge initialisiert. RSACryptoServiceProvider erstellt und mit der Zeile 3 – 4: Die RSA Parameter inklusive des öffentlichen Schlüssels werden mit der Methode ExportCspBlob ausgelesen und an den Client gesendet. Zeile 6 – 14: Nachrichten vom Client werden empfangen, entschlüsselt und ausgegeben. Da die Instanz von RSACryptoServiceProvider den privaten Schlüssel hält, kann einfach die Methode Decrypt aufgerufen werden. Client 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 byte[] publicKey = Convert.FromBase64String(reader.ReadLine()); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportCspBlob(publicKey); while (true) { Console.Write("Enter the string to be transmitted : "); byte[] message = rsa.Encrypt(Encoding.UTF8.GetBytes( Console.ReadLine()), false); streamwriter.WriteLine(Convert.ToBase64String (message)); streamwriter.Flush(); } Listing 30: RSA Verschlüsselung (Client) In Listing 30 werden folgende Aktionen durchgeführt: Zeile 1: Die RSA Parameter inklusive des öffentlichen Schlüssels werden vom Server empfangen. Zeile 3 – 4: Es wird eine Instanz der Klasse RSACryptoServiceProvider erstellt und die empfangenen Parameter werden importiert. Dadurch ist der öffentliche Schlüssel für die spätere Entschlüsselung bekannt. Zeile 6 – 15: Die Daten werden von der Konsole eingelesen, verschlüsselt und an den Server gesendet. 47 Secure .NET Development 5.2.2. Digital Signieren Wie bereits erwähnt, können Daten mithilfe von asymmetrischen Verfahren signiert werden, um die Datenintegrität und die Identität des Absenders überprüfen zu können. Eine digitale Unterschrift hat dieselbe Aufgabe wie eine Unterschrift von Hand, hat jedoch den Vorteil, dass sie nahezu fälschungssicher ist und außerdem den Inhalt der Informationen und die Identität des Unterschreibenden bescheinigt [38, p. 11] Auch beim digitalen Signieren wird ein Schlüsselpaar, also ein öffentlicher und ein privater Schlüssel erzeugt. Um eine Nachricht zu signieren, muss der Sender zuerst einen Hashwert der zu sendenden Information generieren. Eine Hashfunktionen generiert aus einer beliebig großen Eingabe eine Zeichenfolge fixer Länge. Der Hashwert wird danach mit dem privaten Schlüssel verschlüsselt und an die Nachricht angehängt. Der Empfänger erstellt ebenfalls einen Hashwert über die erhaltene Nachricht ohne die Signatur. Zusätzlich entschlüsselt er die Signatur und vergleicht die beiden Werte. Bei einer Übereinstimmung weiß man, dass die Nachricht nicht verändert wurde. [39, pp. 11-12] Um die Identität feststellen zu können, muss das Schlüsselpaar einer Person zugeordnet werden. Dazu werden üblicherweise Zertifikate verwendet, mit denen vertrauenswürdige Stellen diese Zuordnung bestätigen (siehe 5.3). In .NET Applikationen kann zum Signieren wieder die Klasse RSACryptoServiceProvider benutzt werden, welche folgende Methoden bereitstellt: [3, p. 93] SignData: Diese Methode generiert einen Hashwert von den übergebenen Daten und signiert diesen. Als Parameter muss dazu der gewünschte Hash-Algorithmus übergeben werden. SignHash: Diese Methode signiert einen übergebenen Hashwert. Die Methode kommt zum Einsatz, wenn der Hashwert separat berechnet werden soll. VerifyData: Diese Methode überprüft eine mit SignData erstellte Signatur. VerifyHash: Diese Methode überprüft eine mit SignHash erstellte Signatur. Client: 1 2 3 4 5 6 7 8 9 10 11 12 byte[] message = Encoding.UTF8.GetBytes („Inhalt eines Dokuments“); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); byte[] signature = rsa.SignData(message, new SHA1CryptoServiceProvider()); rsa.Clear(); byte[] publicKey = rsa.ExportParameter (false); // Send public key + message + signature to the server Listing 31: RSA Signatur erstellen In Listing 31 werden folgende Schritte durchgeführt: 48 Secure .NET Development Zeile 1: Die zu signierende Nachricht wird in ein Byte Array umgewandelt Zeile 3: Erzeugen einer RSACryptoServiceProvider Instanz samt Schlüsselpaar Zeile 5 – 6: Erzeugen der Signatur: Es wird zuerst ein Hash mithilfe des SHA1 Algorithmus der Nachricht generiert, welcher dann mit dem privaten Schlüssel signiert wird. Zeile 8: Vertrauliche Daten werden gelöscht. Zeile 10: Der öffentliche Schlüssel wird exportiert, da dieser dem Empfänger zur Verfügung gestellt werden muss. Zeile 12: Die Daten (öffentlicher Schlüssel, Signatur und die Nachricht) werden an den Empfänger übermittelt. Um Daten beispielsweise via TCP Verbindung zu versenden, könnten die Schritte den Beispielen in Listing 25 und Listing 26 entnommen werden. Server: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 byte[] publicKey = // Receive public key from client byte[] message = // Receive message from the client byte[] signature = // Receive signature from client RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.importParameters(publicKey); boolean isSignatureCorrect = rsa.VerifyData(message, new SHA1CryptoServiceProvider(),signature); rsa.Clear(); if (isSignatureCorrect) { ... } else { ... } Listing 32: RSA Signatur überprüfen In Listing 32 werden folgende Schritte durchgeführt: Zeile 1: Die Daten (öffentlicher Schlüssel, Signatur und die Nachricht) werden empfangen und abgespeichert. Zeile 5 - 6: Es wird eine Instanz der Klasse RSACryptoServiceProvider erstellt und der empfangenen Schlüssel importiert. Dadurch ist der der öffentliche Schlüssel für die Verifizierung der Signatur bekannt. Zeile 8 – 6: Die Signatur und die erhaltene Nachricht werden verglichen. Dadurch kann festgestellt werden, ob der Inhalt verändert wurde. Zeile 11: Vertrauliche Daten werden gelöscht. Zeile 13 – 20: Je nachdem, ob die Signatur korrekt war, können die gewünschten Aktionen durchgeführt werden. 49 Secure .NET Development 5.3. Digitale Zertifikate Ein digitales Zertifikat kann mit einem Personalausweis in elektronischer Form verglichen werden: Bei einem Personalausweis bestätigt eine vertrauenswürdige Stelle wie zum Beispiel das Meldeamt, dass die Unterschrift auf dem Ausweis auch tatsächlich zu der Person gehört, deren Daten und Bild sich auf dem Ausweis befinden. Bei einem Zertifikat bestätigen vertrauenswürdige Stellen wie beispielsweise GlobalSign die Echtheit von Angaben. [43] Digitale Zertifikate enthalten Informationen wie den Namen des Inhabers, dessen öffentlichen Schlüssel, eine Gültigkeitsdauer und den Namen der Zertifizierungsstelle. Diese Informationen werden in einer ASN.1 (Abstract Syntax Notation One) codierten binären Datei abgespeichert. Um Zertifikate zwischen unterschiedlichen Systemen auszutauschen, muss anstelle der binären Datei ein standardisiertes Format verwendet werden. Hierzu hat sich das Form X.509 durchgesetzt, welches in RFC 3280 beschrieben ist. [39, p. 18] Beim Austausch von Zertifikaten wird gewöhnlich zwischen zwei Formaten unterschieden: .cer Hier handelt es sich um ein signiertes X.509 Zertifikat, welches den öffentlichen Schlüssel und zusätzliche Daten wie beispielsweise die Zertifizierungsstelle enthält. Dieses wird gewöhnlich an den Kommunikationspartner gesendet, damit dieser die Daten mit dem öffentlichen Schlüssel verschlüsseln kann. .pfx (Personal Information Exchange) Hier handelt es sich um ein Zertifikat und den dazugehörigen privaten Schlüssel. Solche Dateien sind sehr vertraulich und werden normalerweise zum Importieren von Schlüsselpaaren auf einem Server verwendet. Um ein Zertifikat zu erhalten, gibt es zwei Möglichkeiten: [44] Wenn das Zertifikat für Internet Szenarien verwendet wird, wird es in den meisten Fällen von einer vertrauenswürdigen Zertifizierungsstelle (CA) angefordert. Solche Zertifikate sind zwar mit Kosten verbunden, haben aber den Vorteil, dass bekannte Browser und Betriebssysteme diese Zertifikate als vertrauenswürdig einstufen. Wenn das Zertifikat nur für Intranet Szenarien verwendet wird, kann eine eigene Zertifizierungsstelle eingerichtet werden, welche auf dem Client als vertrauenswürdig eingestuft wird. Dadurch können Zertifikate selbst erstellt werden. Solche Zertifikate werden auch für B2B Anforderungen eingesetzt. In .NET wird das Zertifikat durch die Klasse X509Certificate2 im System.Security.Crytography.X509Certificates Namensraum repräsentiert. Auf Zertifikate kann entweder über den Windows-Zertifikatsspeicher oder über eine Datei (.cer, .pfx) zugegriffen werden. Mithilfe des Zertifikatsspeichers könnten Zertifikate und ihre dazugehörigen privaten Schlüssel auf verschiedenen Geräten wie z. B. Festplatten, USB-Tokens oder Smartcards gespeichert werden. Der Speicher abstrahiert dabei den physikalischen Speicherort, wodurch immer auf die gleiche Weise zugegriffen werden kann, egal wo das Zertifikat schlussendlich gespeichert ist. Dabei gibt es auf einem Windows System immer zwei Speichertypen: [3, pp. 205, 206] 50 Secure .NET Development Benutzerzertifikatsspeicher: Dieser wird nur für den jeweils angemeldeten Benutzer verwendet und kann mit dem Befehl certmgr.msc aufgerufen werden. Computerzertifikatsspeicher: Dieser Speicher wird von Windows Computerkonten wie NETZWERK, LOKALER DIENST und LOKALES SYSTEM verwendet. Zusätzlich können damit Zertifikate oder Schlüssel für mehrere Konten gemeinsam bereitgestellt werden. Wie in Abbildung 15 veranschaulicht, ist der Speicher in verschiedene Unterelemente unterteilt: Es gibt beispielsweise einen Container mit dem Namen „Eigene Zertifikate“, in dem eigenen Zertifikate, welche einen zugeordneten privaten Schlüssel haben verwaltet werden. Ein anderer Container mit den Namen „Vertrauenswürdige Stammzertifizierungsstellen“ enthält die Zertifikate aller Zertifizierungsstellen, denen vertraut wird. [3, pp. 205, 206] Abbildung 15: Benutzerzertifikatsspeicher 5.3.1. Verschlüsseln Da nun alle theoretischen Fakten erklärt wurden, wird im nachfolgenden Beispiel mittels einer Client-Server Applikation das Ver- und Entschlüsseln mit Zertifikaten gezeigt. Die Client Applikation verschlüsselt die Daten, wodurch auf diesem System das Zertifikat mit dem öffentlichen Schlüssel (.cer) installiert sein muss. Der Server muss zum Entschlüsseln der Daten einen Zugriff auf den privaten Schlüssel (.pfx) haben. In diesem Beispiel wurde das Zertifikat sowohl am Client als auch am Server im Benutzerzertifikatsspeicher unter „Eigene Zertifikate“ gespeichert. Die Schritte zum Senden und Empfangen über einen TCP Port können dem Beispiel aus Listing 25 und Listing 26 übernommen werden. Client: 51 Secure .NET Development 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection certs = Store.Certificates.Find( X509FindType.FindByIssuerDistinguishedName, "CN=testing.com", true); X509Certificate2 cert = null; if (col.Count > 0) cert = col[0]; else return; while (true) { Console.Write("Enter the string to be transmitted : "); byte[] input = Encoding.UTF8.GetBytes(Console.ReadLine()); ContentInfo plainMessage = new ContentInfo(input); EnvelopedCms encryptMessage = new EnvelopedCms(plainMessage); encryptMessage.Encrypt(new CmsRecipient(cert)); writer.WriteLine(Convert.ToBase64String(encryptMessage.Encode())); writer.Flush(); } Listing 33: Verschlüsseln mit Zertifikaten In Listing 33 werden folgende Schritte durchgeführt: Zeile 1 – 2: Der Container “Eigene Zertifikate” im Benutzerzertifikatsspeicher wird geöffnet. Zeile 4 – 5: In dem geöffneten Container wird nach allen gültigen Zertifikaten gesucht, welche von “testing.com” herausgegeben wurden. Im ersten Parameter kann eine Reihe von Suchtypen wie Serial Nummer, öffentlicher Schlüssel, usw. angegeben werden. Der zweite Parameter gibt den dazugehörigen Suchwert an. Im letzten Parameter wird spezifiziert, dass nur gültige Zertifikate gesucht werden sollen. Zeile 7 – 11: Es wird überprüft, ob ein Zertifikat gefunden wurde. Wenn nicht, so wird das Programm beendet. Zeile 15 – 16: Die Daten werden von der Konsole eingelesen und in ein Byte Array konvertiert. Zeile 18: Es wird eine ContentInfo Instanz erzeugt und mit dem Klartext initialisiert. Dies ist notwendig, da dieses Objekt eine Datenstruktur für Cryptographic Message Syntax (CMS) darstellt. CMS ist ein weit verbreitetes Format für kryptographische Nachrichten. [45] Zeile 19 - 20: Es wird eine EnvelopedCms Instanz erzeugt, welches die verschlüsselten Daten repräsentiert. Zum Verschlüsseln benötigt das Objekt den Klartext in Form einer ContentInfo Klasse, welche beim Instanziieren an den Konstruktor übergeben wird. Die Methode Encrypt führt die Verschlüsselung durch. Als Parameter wird ein Zertifikat mit dem öffentlichen Schlüssel in Form einer CmsRecipient Klasse übergeben. Intern werden die Daten mit einem zufällig generierten Session Key symmetrisch verschlüsselt. Der Session Key wird dann mit dem öffentlichen Schlüssel verschlüsselt. Die zugelieferten Daten enthalten die verschlüsselte Nachricht sowie Informationen über den öffentlichen Schlüssel, damit beim Entschlüsseln der dazugehörige private Schlüssel zugeordnet werden kann. [3, p. 215] Zeile 22 – 23: Die verschlüsselte Nachricht wird an den Server gesendet 52 Secure .NET Development Server 1 2 3 4 5 6 7 8 9 10 11 while (true) { Byte[] message = Convert.FromBase64String(reader.ReadLine()); EnvelopedCms decryptedMessage = new EnvelopedCms(); decryptedMessage.Decode(message); decryptedMessage.Decrypt(); Console.WriteLine("Received: " + Encoding.UTF8.GetString( decryptedMessage.ContentInfo.Content)); } Listing 34: Entschlüsseln mit Zertifikaten In Listing 34 werden folgende Schritte durchgeführt: Zeile 3: Die verschlüsselten Daten vom Client werden empfangen und in ein Byte Array umgewandelt. Zeile 5 – 5: Die chiffrierten Nachrichten werden mithilfe des EnvelopedCms Objekts entschlüsselt. Wie man sehen kann, muss hierzu kein Zertifikat angegeben werden. Da die verschlüsselten Daten auch den öffentlichen Schlüssel enthalten, kann die Klasse intern nach dem dazugehörigen privaten Schlüssel suchen. Voraussetzung ist natürlich, dass das Zertifikat mit dem privaten Schlüssel am System installiert wurde. Zeile 9 – 10: Die entschlüsselten Daten werden in der Konsole ausgegeben. 5.3.2. Digital Signieren Wie bereits unter 5.2.2 erwähnt, werden Signaturen verwendet, um Daten gegen Manipulation zu schützen. Dazu wurde bereits ein praktisches Beispiel gezeigt, indem die Daten mit einem SHA1 Hash Algorithmus und RSA Verschlüsselung signiert wurden. Der Empfänger konnte durch die Signatur überprüfen, ob die Daten während der Übertragung verändert wurden. Jedoch konnte der Empfänger nicht sicherstellen, ob der Kommunikationspartner auch wirklich der ist, für den er sich ausgibt (Prüfung der Identität). Bei sensiblen Tätigkeiten wie dem Senden und Empfangen von Geschäftsnachrichten (E-Mails) oder Online Banking muss sichergestellt sein, dass auch wirklich mit dem geglaubten Gegenüber kommuniziert wird. Um dies zu gewährleisten, können digitale Zertifikate verwendet werden. Möchte eine Person Dokumente oder E-Mails digital unterschreiben, so müssen folgende Schritte durchgeführt werden: Die Person muss bei einer Zertifizierungsstelle (Certification Authority, CA) um ein Zertifikat zum digitalen Signieren ansuchen. Bevor die CA ein Zertifikat ausstellt, muss die Identität mittels Personalausweis überprüft werden. Nachdem die Identität bestätigt wurde, wird ein Zertifikat mit einem öffentlichen und einem privaten Schlüssel für den Nutzer erstellt. Beim Senden einer E-Mail oder eines Dokuments fügt der Absender eine digitale Signatur hinzu. 53 Secure .NET Development Durch die digitale Signatur kann der Empfänger den öffentlichen Schlüssel auslesen. Dadurch kann er bei der verantwortlichen CA überprüfen, ob es sich tatsächlich um den angegebenen Absender handelt. Bei diesem Prozess wird vorausgesetzt, dass der Empfänger der verantwortlichen CA vertraut. Abbildung 16: E-Mail Signatur überprüfen In der Abbildung 16 wird die Signatur einer E-Mail überprüft. Dabei soll festgestellt werden, dass die E-Mail Adresse [email protected] auch wirklich zu der Identität Patrick Riedl gehört. Wie man im dazugehörigen Zertifikat sieht, wurde von der CA GlobalSign die Identität für Herrn Patrick Riedl bestätigt. Das Signieren mit Zertifikaten in .NET funktioniert ähnlich wie das Ver- und Entschlüsseln mit Zertifikaten (siehe 5.3.1). Der einzige Unterschied ist, dass anstelle der Klasse EnvelopedCms nun die Klasse SignedCms verwendet wird. Um das Beispiel von Listing 33 und Listing 34 mit einer Signatur zu erweitern, müssen folgende Anpassungen durchgeführt werden: Client: 1 2 3 4 5 6 ContentInfo content = new ContentInfo(input); SignedCms signedMessage = new SignedCms(content); signedMessage.ComputeSignature (new CmsSigner(cert)); byte[] signedBytes = signedMessage.Encode(); // Encrypt und transfer signedByte to the server Listing 35: Signatur mit einen Zertifikat erstellen 54 Secure .NET Development In Listing 35 werden folgende Schritte durchgeführt: Zeile 1: Die eingelesenen Daten werden nun vor dem Verschlüsseln signiert. Dazu wird wieder eine Instanz von ContentInfo erstellt, um die Daten in einer CMS Datenstruktur abzuspeichern. Zeile 2 – 3: Um die Daten zu signieren, wird eine Instanz von SignedCms erstellt, welche die signierten Daten repräsentiert. Zum Signieren benötigt das Objekt den Klartext in Form einer ContentInfo Klasse, welche beim Instanziieren an den Konstruktor übergeben wird. Die Methode ComputeSignature generiert den Hashwert und verschlüsselt diesen mit dem privaten Schlüssel. Als Parameter wird daher ein Zertifikat mit dem privaten Schlüssel in Form einer CmsSigner Klasse übergeben. Server: 1 2 3 4 5 6 7 // Decrypt received data SignedCms signedMessage = new SignedCms(); signedMessage.Decode(encryptedMessage.ContentInfo.Content); signedMessage.CheckSignature(false); foreach (SignerInfo signer in signedMessage.SignerInfos) Console.WriteLine("Aussteller " + signer.Certificate.IssuerName.Name); Listing 36: Signatur überprüfen In Listing 36 werden folgende Schritte durchgeführt: Zeile 1: Die Daten werden empfangen und müssen mit dem privaten Schlüssel entschlüsselt werden. (siehe Listing 34) Erst danach kann eine Integritätsprüfung durchgeführt werden. Zeile 3: Um nun die Signatur und das Zertifikat zu überprüfen, wird die Klasse SignedCms verwendet. Um eine Überprüfung zu starten, müssen zuvor die CMS/PKCS #7 Daten deserialisiert werden. Zeile 4: Nun können die Signatur und das Zertifikat überprüft werden. Möchte man nur die Signatur überprüfen, so muss der Parameter true übergeben werden. Tritt bei der Validierung ein Fehler auf, so wird eine Exception ausgelöst. Zeile 5 – 6: Über das SignedCms Objekt kann auch auf das dazugehörige Zertifikat zugegriffen werden. Zum Demonstrieren wird hier der Aussteller des Zertifikats ausgegeben. 55 Secure .NET Development 6. Reverse Engineering Beim Reverse Engineering wird versucht, einen kompilierten Code in den originalen Quellcode zurück zu bringen. Dadurch können Angreifer eine Menge an Informationen gewinnen: Es können logische Abläufe, eingesetzte Methoden oder sensible Informationen wie hartcodierte Passwörter ausgelesen werden. Zusätzlich kann durch Reverse Engineering das Know-How gestohlen werden, wodurch ein großer Schaden entstehen kann. [46] Das Dekompilieren von Unmanaged Code wie C/C++ Anwendungen ist sehr schwierig, da beim Kompilieren der Maschinencode generiert wird. Bei Managed Applikationen wie .NET ist es hingegen sehr einfach, da nur ein Zwischencode (MSIL) erzeugt wird, welcher dann vom Just-in-time Compiler in den Maschinencode übersetzt wird. (siehe 2.1) Da der MSIL Code sehr gut dokumentiert ist, gibt es einige Tools, mit denen eine .NET DLL (Dynamic Link Library) oder eine EXE (Executable) rückwärtskompiliert werden kann. [47] Dazu werden sowohl kommerzielle als auch kostenlose Programme angeboten: JetBrains dotPeek: kostenloser .NET Decompiler Dotnet IL Editor (DILE): kostenlos – ermöglicht das Dekompilieren und Debuggen von .NET Anwendungen ILSpy: kostenloser und Open Source Decompiler Redgate .NET Reflector: kommerziell - ermöglicht das Dekompilieren und Debuggen von .NET Anwendungen Um nun eine .NET Anwendung zu dekompilieren, muss lediglich eines der genannten Tools geöffnet und die gewünschte Datei (.dll oder .exe) ausgewählt werden. 56 Secure .NET Development Abbildung 17: Dekompilierte Applikation Abbildung 18: Originaler Source Code 57 Secure .NET Development Wenn man die Abbildung 17 und Abbildung 18 vergleicht, kann man erkennen, dass durch das Dekompilieren der originale Code ohne große Unterschiede ermittelt werden konnte. So konnten beispielsweise die Zugangsdaten für die SQL Verbindung ausgelesen werden. 6.1. Gegenmaßnahmen Um Applikationen vor Reverse Engineering zu schützen, können sogenannte Obfuscating Techniken eingesetzt werden. Dadurch wird ein gut lesbarer Quellcode in einen schwer lesbaren Code umgewandelt. [48] Es gibt zwar keine 100%ige Sicherheit gegen das Dekompilieren, jedoch kann man es durch Obfuscating einem Angreifer so schwer machen, damit der Aufwand zum Cracken so hoch ist, dass es nicht mehr interessant ist. Obfuscator führen folgende Operationen durch: [49] Symbole umbenennen Um Informationen wie die Namen von Variablen, Funktionen oder Klassen zu schützen, werden diese Benennungen in nichts aussagende Namen umgewandelt. Dadurch können Programmroutinen von einem Angreifer nicht nachvollzogen werden. Verschlüsselung von Zeichenketten Wie in Beispiel von Abbildung 18 zu sehen ist, werden innerhalb des Quellcode die Zugangsdaten zu einer Datenbank angegeben. Um solche Daten zu schützen, werden Zeichenketten während des Obfuscatings verschlüsselt. Verschlüsselung von Ressourcen Anwendungen haben in der Regel unterschiedliche Ressourcen wie Grafiken oder Konfigurationsdateien eingebunden. Um auch diese vor unerlaubten Zugriffen zu schützen, können diese verschlüsselt werden. Schutz gegen Reflection Decompiler nutzen häufig Reflections, um Informationen über eine .NET Anwendung zu gewinnen. Durch Obfuscating kann eine Applikation so verändert werden, dass beim Benutzen von Reflections ein Fehler ausgelöst wird. Je nach eingesetztem Tool für den Obfuscating Prozess werden oftmals noch weitere Features angeboten. Die meisten Obfuscator sind zwar nicht kostenlos, bieten aber dafür jede Menge an Features zum Absichern einer Applikation. Zum professionellen Einsatz gehören Tools wie Crypto Obfuscator for .NET (von LogicNP Software) oder Dotfuscator for .NET (von PreEmptive). Wenn man zum Beispiel den Obfuscator „Crypto Obfuscator for .NET“ auf das Beispiel von Abbildung 18 anwendet, so würde nach dem Dekompilieren folgendes Ergebnis erzeugt: 58 Secure .NET Development Abbildung 19: Reverse Engineering nach Obfuscating Wie man in der Abbildung 19 sehen kann, wurde der Quellcode so verschleiert, dass weder die Namen für Variablen oder Funktionen noch der Inhalt der Variablen ersichtlich sind. 59 Secure .NET Development 7. Deployment 7.1. Konfigurationsdaten Häufig hat man das Problem, dass zwar grundsätzlich sichere Software eingesetzt wird, jedoch Konfigurationsdateien mit Zugangsdaten unverschlüsselt abgespeichert werden. Dadurch sind die Sicherheitsmechanismen der Software überflüssig, da so der Zugriff auf Daten bzw. Dienste auch außerhalb der Software möglich wird. Beim Absichern einer Konfiguration muss zwischen Clientanwendungen und Webanwendungen unterschieden werden: Bei Clientanwendungen muss die Konfiguration auf jedem Computer vorhanden sein, wo die Anwendung gestartet wird. Dies ist bei Webanwendungen nicht notwendig, da die Applikation zentral auf einer Maschine (Webserver) läuft. 7.1.1. Clientanwendungen Kommuniziert eine Clientanwendung (z.B. Desktopapplikation) mit einer Datenbank oder einem Webservice, so muss die Applikation über die entsprechenden Verbindungsdaten verfügen. Heikle Informationen wie Zugangsdaten sollten dabei auf keinen Fall im Klartext gespeichert werden, da ansonsten ein Benutzer die Berechtigungen der Software umgehen kann. Um dies zu gewährleisten, gibt es zwei Möglichkeiten: Entweder die sensiblen Daten werden in der Applikation hartcodiert angegeben oder die Konfigurationsdatei wird verschlüsselt. Entscheidet man sich für den ersten Ansatz, so sollte die Applikation unbedingt vor Reverse Engineering Attacken geschützt werden (siehe Kapitel 6). Beim zweiten Ansatz ist die Schwierigkeit, dass die Applikation den Schlüssel zum Entschlüsseln benötigt. Da dieser in den meisten Fällen auch hartcodiert angegeben wird, sollte auch hier die Applikation gegen das Dekompilieren geschützt werden. 7.1.2. Webanwendungen Bei Webanwendungen ist dieser Vorgang etwas einfacher, da die Konfiguration und die Applikation zentral abgelegt sind. Um die Sicherheit der Webanwendung zu erhöhen, können sensible Daten in der web.config verschlüsselt werden. [50] Sollte ein Angreifer Zugriff auf die Konfigurationsdatei bekommen, so wäre dieser völlig nutzlos, da er die Daten nicht entschlüsseln könnte. Die Verschlüsselung wird üblicherweise mit einem bereitgestellten Verschlüsselungsmechanismus durchgeführt. Dazu kann entweder der RsaProtectedConfigurationProvider oder der DpapiProtectedConfigurationProvider verwendet werden, wobei standardmäßig der RSA Algorithmus eingesetzt wird. Beim zweiten Provider wird mithilfe der DPAPI (Data Protection API) ver- und entschlüsselt. Die DPAPI ist Bestandteil eines Windows Betriebssystem, welches die Aufgabe der Schlüsselverwaltung übernimmt. Bei Bedarf kann auch ein eigener Provider entworfen und verwendet werden. [51] 60 Secure .NET Development Bei jeder Installation des .NET Frameworks wird ein RSA Key Container mit dem Namen NetFrameworkConfigurationKey mitinstalliert. In diesem befindet sich ein öffentlich/privates Schlüsselpaar, welches für die Ver- und Entschlüsselung der Konfigurationsabschnitte verwendet wird. [52] Da dieser Schlüssel bei jeder Installation unterschiedlich ist, kann die Konfiguration nur auf der gleichen Maschine verwendet werden. Besteht der Bedarf, auf mehreren Maschinen dieselbe verschlüsselte Konfiguration zu verwenden, so kann ein eigener Container generiert und auf andere Maschinen importiert werden. [53] Damit aus einer Webanwendung direkt auf die verschlüsselte Konfiguration zugegriffen werden kann, muss die „Application Pool Identity“ der Webapplikation eine Leseberechtigung für den entsprechenden Container haben. [51] Dies kann mit Befehl aspnet_regiis durchgeführt werden, welcher unter C:\Windows\Microsoft.NET\Framework\<Version> zu finden ist: 1 aspnet_regiis -pa "<Name des Container>" "<Benutzername>" Um Daten in der Konfiguration zu verschlüsseln, muss keine einzige Zeile Code geschrieben werden, da der gesamte Prozess mit der Konsole durchgeführt werden kann. Dazu muss wieder der Befehl aspnet_regiss verwendet werden, welcher als Parameter den gewünschten Abschnitt in der Konfiguration sowie den Name der Webapplikation benötigt: 1 aspnet_regiis -pe "<Konfigurationsabschnitt>" -app "<Webapplikation>" Um beispielsweise den ConnectionString der Webapplikation „SecureWebapplication“ zu verschlüsseln, muss der folgende Befehl ausgeführt werden: 1 aspnet_regiis.exe -pe "connectionStrings" -app "SecureWebapplikation" Möchte man den ConnectionString nachträglich ändern, so muss der Konfigurationsabschnitt zuerst entschlüsselt und danach entsprechend angepasst werden. Danach kann die Verschlüsslung erneut durchgeführt werden: 1 7.2. aspnet_regiis.exe -pd "connectionStrings" -app "SecureWebapplikation" Strong Names Bei größeren Softwareprojekten werden Abläufe oder Routinen häufig in Bibliotheken wie DLLs (Dynamic Link Library) ausgelagert, da diese später in anderen Projekten wiederverwendet werden können. Solche Bibliotheken werden zur Laufzeit von der jeweiligen Applikation geladen. Würde es einem Angreifer gelingen, eine Bibliothek so zu manipulieren, dass zusätzlich zum ursprünglichen Code auch noch ein Schadcode ausgeführt wird, so wäre die Applikation kompromittiert. Um dies zu verhindern, können Komponenten mit einem sogenannten Strong Name signiert werden. [54] Durch einen Strong Name erhält eine Komponente eine global eindeutige Identität, welche aus einem Namen (z.B. Name der Bibliothek), der Version und Kulturinformation sowie einem öffentlichen Schlüssel und einer digitalen Signatur besteht. [55] 61 Secure .NET Development Ein Strong Name kann mithilfe des Visual Studio sehr einfach erstellt werden. Dazu sind folgende Schritte durchzuführen: die Eigenschaften des Projekts aufrufen (Rechtsklick auf das Projekt – Eigenschaften/Properties) in der linken Spalte den Menüpunkt “Signierung/Signing” auswählen die Option “Assembly signieren/Sign the assembly” setzen - Zusätzlich muss ein Key File angegeben werden, welches den privaten und öffentlichen Schlüssel enthält. Bei Bedarf kann der Schlüssel auch hier erzeugt werden. Abbildung 20: Signieren einer .NET Bibliothek Die Version und Kulturinformationen können unter “Anwendung – Assembly Informationen” angegeben werden. 62 Secure .NET Development Abbildung 21: Information einer Assembly setzen Nachdem die Bibliothek erstellt worden, kann diese in andere Applikationen eingebunden werden. Wird die eingebundene Komponente manipuliert, wird folgende Exception ausgelöst: Abbildung 22: Exception bei manipulierten Bibliotheken 7.3. ClickOnce-Bereitstellung ClickOnce wurde von Microsoft entwickelt und dient zum Verteilen von .NET Anwendungen (WinForms, WPF) über das Netzwerk. [56] Klein- oder Mittelunternehmen besitzen häufig keine Systeme für Software Rollouts, wodurch das Verteilen und die Wartung von Applikationen sehr mühsam ist. Mit ClickOnce kann ein Link bereitgestellt werden, über den sich die Benutzer eine Applikation selbst installieren können. Dieser benötigt keine Administrationsberechtigungen, da die Anwendung in einem Benutzerverzeichnis installiert wird. Dadurch kann die Anwendung nur vom aktuellen Benutzer genutzt werden. Ein weiteres Feature von ClickOnce ist der mitgelieferte Aktualisierungsprozess. Bei jedem Start einer ClickOnce Anwendung wird überprüft, ob eine neue Version bereitsteht. Wenn ja, wird die alte Version automatisch deinstalliert und die neue installiert. [56] So können Updates rasch und unkompliziert ausgerollt werden. Um eine Anwendung mithilfe von ClickOnce bereitzustellen, müssen folgende Schritte durchgeführt werden: in Visual Studio in die Projekteigenschaften der gewünschten Applikation wechseln auf der linken Seite den Menüpunkt „Veröffentlichen/Publish“ auswählen 63 Secure .NET Development Abbildung 23: Applikation mittels ClickOnce bereitstellen Informationen zu den Optionen können unter http://openbook.galileocomputing.de/visual_csharp_2010/visual_csharp_2010_30_002.htm#mjaa7397 d5ca453f2628726d80fab473f3 http://msdn.microsoft.com/de-de/library/142dbbz4(v=vs.90).aspx nachgelesen werden. Mit ClickOnce werden auch sicherheitstechnische Aspekte wie die Signierung von Anwendungs- und Bereitstellungsmanifesten unterstützt. Details dazu können unter http://msdn.microsoft.com/enus/library/zfz60ccf(v=vs.80).aspx abgerufen werden. 64 Secure .NET Development 8. Konzeptionierung eines Secure Coding Demonstrators Im Zuge dieser Arbeit wurde ein .NET Demonstrator entwickelt, um die gezeigten Schwachstellen und Lösungen auch in Schulungen bzw. Trainings präsentieren zu können. 8.1. Web Security Es wurden zwei Webapplikationen entwickelt, welche typische Anwendungsfälle wie Benutzeranmeldung oder benutzerspezifische Datenverwaltung abbilden. Beide Applikationen besitzen zwar das gleiche Design und dieselben Funktionalitäten, jedoch wurden bei einer Anwendung die hier beschriebenen Best Practice Ansätze verwendet. Bei der Anderen wurden auf jegliche Sicherheitsfunktionalitäten verzichtet. Durch ein ausgeklügeltes Demo-Szenario können die Benutzer die unsichere Anwendung Schritt für Schritt angreifen und somit unberechtigt Zugriff auf Daten erlangen. Die Applikation demonstriert ein Portal zum Verwalten von Meilen, wobei die Meilen für ein Prämienmodell á la Miles and More verwendet werden. Meilen können von Mitarbeitern beantragt werden, indem sie einen Event Eintrag erstellen. Dieser Eintrag besteht aus einem Eventname und Eventtyp (z.B. Buch gelesen, Schulung teilgenommen, Wiki-Eintrag geschrieben). Die gesammelten Meilen können dann entweder gegen Produkte eingetauscht oder an andere Benutzer übertragen werden. Ist der angemeldete Benutzer Mitglied der Administrator-Rolle, so können administrative Funktionen, wie das Verwalten von Benutzern, von Produkten, usw. ausgeführt werden. In der Tabelle 4 werden alle Funktionen der Anwendung aufgelistet. Funktion Meilen beantragen Meilen inklusive Status abrufen Meilen bearbeiten und entfernen Status von Meilen vergeben Meilen an andere Benutzer übertragen Produkte erstellen, bearbeiten und entfernen Produkte kaufen Gekaufte Produkte auflisten Eventtypen erstellen, bearbeiten und entfernen Benutzer erstellen und entfernen Passwort zurücksetzen Übersicht über alle Meilen-Transaktionen abrufen Berechtigung Mitarbeiter, Administrator Mitarbeiter: nur die eigenen Meilen Administrator: alle Meilen Mitarbeiter: nur die eigenen Meilen Administrator: alle Meilen Administrator Mitarbeiter, Administrator Administrator Mitarbeiter, Administrator Mitarbeiter: nur die eigenen Produkte Administrator: alle Produkte Administrator Administrator Mitarbeiter: nur das eigene Passwort Administrator: alle Passwörter Mitarbeiter, Administrator Tabelle 4: Funktionalitäten der Demo Webapplikation Um die unsichere Webapplikation nun anzugreifen, können folgende Schritte durchgeführt werden: Login: Da unsichere Datenbankzugriffe implementiert wurden, kann hier eine SQL Injection durchgeführt werden. 65 Secure .NET Development Erstellen von Meilen: Da die eingegebenen Daten eins zu eins in die Datenbank übernommen werden, kann man hier eine XSS Attacke anwenden. Auflisten der Meilen: Die aufgelisteten Meilen können mithilfe eines Suchfilters eingeschränkt werden. Dieser Filter kann für eine SQL Injection missbraucht werden, um beispielsweise Daten von anderen Benutzern abzufragen. Weiters können Details der Datenbank mittels Blind SQL Injection ermittelt werden. Übertragen von Meilen: Mittels einer CSRF Attacke kann sich ein Angreifer Meilen von seinem Opfer auf sein Konto übertragen. Abrufen der Meilen-Transaktionen: Um die Transaktionsliste von einem anderen Benutzer anzuzeigen, kann eine Direct Object References Schwachstelle ausgenutzt werden. Login Meilen beantragen Meilen abrufen Meilen einlösen/übertragen Transaktionen abrufen Abbildung 24: Herkömmlicher Ablauf des Web Security Demonstrators Login SQL Injection Meilen beantragen XSS Attacke Meilen abrufen Blind SQL Injection Meilen einlösen/übertragen CSRF Attacke Transaktionen abrufen Direct Object Reference Attacke Abbildung 25: Angriffsvektoren des Web Security Demonstrators 8.2. Kryptographie Der Demonstrator für die vorgestellten kryptografischen Techniken besteht aus einer Client und einer Server Anwendung, welche über einen TCP Port kommunizieren. Für jede Verschlüsselungsart wurde eine eigene Klasse implementiert, wobei jede Klasse die Methode Start() besitzt. Dadurch können in Schulungen die Verschlüsselungsarten einfach und schnell präsentiert werden, weil nur die gewünschte Klasse instanziiert und die Start Methode ausgeführt werden muss. Wie man in Listing 37 sieht, werden die gerade nicht benötigten Verschlüsselungsalgorithmen auskommentiert, damit nur die gewünschte Verschlüsselung zum Einsatz kommt. Am Server muss natürlich auch die dazu passende Methode aufgerufen werden. 1 2 3 4 5 6 7 SymmetricClient symmetricClient = new SymmetricClient(); SymmetricDhClient symmetricDhClient = new SymmetricDhClient(); AsymmetricClient asymmetricClient = new AsymmetricClient(); CertificateClient certEncryptClient = new CertificateClient(); // symmetricClient.Start(); // symmetricDhClient.Start(); 66 Secure .NET Development 8 9 // asymmetricClient.Start(); certEncryptClient.Start(); Listing 37: Demonstrator: Start des gewünschten Verschlüsselungsalgorithmus Da die Kommunikation über TCP läuft, kann ein Netzwerk Sniffer verwendet werden, um die ausgetauschten Daten zu analysieren. 8.3. WCF Gleich wie bei dem Demonstrator für Kryptographie wurde auch für WCF eine Client/Server Applikation entwickelt. Dadurch können die ausgetauschten Daten mithilfe eines Netzwerk Sniffer nachvollzogen werden. Somit kann man demonstrieren, dass bei einer unsicheren Endpoint Konfiguration die Daten im Klartext übertragen werden. 67 Secure .NET Development 9. Zusammenfassung & Ausblick Anhand dieser Arbeit kann erkannt werden, dass das .NET Framework eine sehr mächtige Laufzeitumgebung ist, welche eine Menge an Sicherheitsfeatures mitliefert. Es wurde gezeigt, wie typische Webschwachstellen wie beispielsweise Cross-Site-Scripting oder SQL Injection mittels .NET Framework verhindert werden können. Weiters wurde gezeigt, wie die Kommunikation mit ASP.NET Webservices und WCF Anwendungen sicher umgesetzt werden kann. Auch das Thema Kryptographie wurde detailliert behandelt. Dazu wurden .NET Bibliotheken sowohl theoretisch als auch praktisch vorgestellt, um Daten zu verschlüsseln, entschlüsseln und signieren. Zu guter Letzt wurde auch ein Einblick in Reverse Engineering und sicheres Deployment gegeben, um fertige Anwendungen sicher bereitstellen zu können. Das Thema wird weiterhin von Bedeutung sein, gerade weil vor kurzem wieder neue .NET Features vorgestellt wurden: ASP.NET (ASP vNext) enthält weitere Cloud Optimierung und läuft nun neben Windows auch auf Linux und Mac OS. Dazu könnten in weiteren Arbeiten die angebotenen Sicherheitslösungen für Cloud Anwendungen untersucht werden. Auch die Unterstützung von Cross-Device Entwicklung wurde weiter verbessert, wodurch der gleiche Code auf unterschiedlichen Geräten wie Phone, Tablet, Desktop und Xbox verwendet werden kann. Dazu wäre interessant zu erforschen, inwieweit auch Sicherheitsfeatures geräteübergreifend eingesetzt werden können. Das .NET Framework wird sich auch in Zukunft rasant weiterentwickeln, um Entwickler bei den neuen IT Trends zu unterstützen. Aus diesem Grund kann diese Arbeit als Grundlage für die Entwicklung von sicheren .NET Applikationen oder weitere wissenschaftliche Arbeiten zu diesem Thema verwendet werden. 9.1. Weitere Fehlerquellen Trotz der vielen vorgestellten Maßnahmen kann nicht garantiert werden, dass erfolgreiche Attacken auf eine Anwendung unmöglich sind. Durch die rasante technische Entwicklung werden täglich neue Angriffsmöglichkeiten entdeckt, wodurch Sicherheitsmechanismen ausgehebelt werden können. Läuft eine Webapplikation beispielsweise auf einem veralteten Webserver, so könnte ein Angreifer Sicherheitslücken des Servers ausnutzen, um unberechtigt auf die Daten der Anwendung zuzugreifen. Aus diesem Grund sollten Systeme wie das Betriebssystem, das Datenbanksystem oder der Webserver immer mit den aktuellsten Sicherheitspatches vorsorgt werden. Es ist auch zu beachten, dass eine Webanwendung mit einem eingeschränkten Benutzerkonto ausgeführt werden sollte. Dadurch kann ein Angreifer bei einer erfolgreichen Attacke nur beschränkt Aktionen am betroffenen System ausführen. Bei größeren Softwareprodukten werden meist auch externe Bibliotheken von unterschiedlichen Herstellern verwendet. Diese sollten regelmäßig auf Updates geprüft werden, um Fehler und Sicherheitslücken rasch zu beheben. Externe Bibliotheken für das .NET Framework werden häufig über NuGet veröffentlicht, wodurch eine einfache Paketverwaltung in Visual Studio ermöglicht wird. Zuletzt muss noch gesagt werden, dass menschliche Fehler und Missbräuche nicht außer Acht gelassen werden dürfen. Es kommt immer wieder vor, dass vertrauliche Daten von internen Mitarbeitern an Außenstehende weiterverkauft werden. Dadurch können Konkurrenzunternehmen oder kriminelle Organisationen Zugriff auf geheime Daten erlangen und diese für unerwünschte Zwecke gebrauchen. Daher sollten alle Unternehmen lückenlose Verträge besitzen, um gegen solche Verstöße rechtlich vorgehen zu können. 68 Secure .NET Development Literaturverzeichnis [1 R. Siciliano, „infosec ISLAND,“ Wired Business Media, 22 April 2011. [Online]. Available: ] http://www.infosecisland.com/blogview/13075-Software-Security-Incidents-Cost-an-Average300000.html. [Zugriff am 03 April 2014]. [2 D. Rice, Geekonomics: The Real Cost of Insecure Software, Boston: Addison-Wesley Professional, ] 2008. [3 S. Zahedani, Sichere Software mit Microsoft .NET entwickeln, Frankfurth am Main: Software & Support ] Verlag GmbH, 2007. [4 Microsoft, „Overview of the .NET Framework,“ ] http://www.microsoft.com/net. [Zugriff am 04 04 2014]. Microsoft, [Online]. Available: [5 Xamarin , „mono,“ Xamarin , [Online]. Available: http://www.mono-project.com. [Zugriff am 04 04 2014]. ] [6 Microsoft Corporation, „Programmiersprachen,“ Microsoft Corporation, [Online]. ] http://msdn.microsoft.com/de-de/library/aa292164(v=vs.71).aspx. [Zugriff am 7 4 2014]. Available: [7 ITWissen, „CTS (common type system),“ ITWissen, [Online]. Available: ] http://www.itwissen.info/definition/lexikon/CTS-common-type-system.html. [Zugriff am 8 4 2014]. [8 Microsoft Corporation, „Common Type System,“ Microsoft Corporation, [Online]. Available: ] http://msdn.microsoft.com/en-us/library/vstudio/zcx1eb1e(v=vs.100).aspx. [Zugriff am 7 4 2014]. [9 Microsoft Corporation, „.NET Framework Class Library,“ Microsoft Corporation, 12 2009. [Online]. ] Available: http://msdn.microsoft.com/en-us/library/vstudio/ms229335(v=vs.90).aspx. [Zugriff am 9 6 2014]. [1 W. Fischereder, „The Common Intermediate Language (CIL),“ [Online]. Available: http://www.ssw.uni0] linz.ac.at/Teaching/Lectures/Sem/2003/reports/Fischereder/Fischereder.pdf. [Zugriff am 9 6 2014]. [1 Microsoft Corporation, „Common Language Runtime (CLR),“ Microsoft Corporation, [Online]. Available: 1] http://msdn.microsoft.com/de-de/library/8bs2ecf4(v=vs.110).aspx. [Zugriff am 9 6 2014]. [1 A. Adya, J. A. Blakeley, S. Melnik, und S. Muralidhar, „Anatomy of the ADO.NET Entity Framework,“ in 2] SIGMOD '07, Beijing, China, 2007. [1 „ADO.NET Entity Framework Architecture,“ 9 4 2012. [Online]. Available: http://csharp3] guide.blogspot.co.at/2012/05/adonet-entity-framework-architecture.html. [Zugriff am 9 04 2014]. [1 P. Pialorsi und M. Russo, Introducing Microsoft Linq, Redmond, WA, USA: Microsoft Press, 2007. 4] [1 D. Fox, „Cross Site Scripting (XSS),“ DuD - Datenschutz und Datensicherheit, Nr. 11, 11 2012. 5] [1 OWASP Foundation, „Cross-site Scripting (XSS),“ OWASP Foundation, 22 4 2014. [Online]. Available: 6] https://www.owasp.org/index.php/Cross-site_Scripting_(XSS). [Zugriff am 9 6 2014]. [1 OWASP Foundation, „SQL Injection,“ OWASP Foundation, 12 4 2014. [Online]. Available: 7] https://www.owasp.org/index.php/SQL_Injection. [Zugriff am 9 6 2014]. [1 Microsoft Corporation, „ADO.NET Data Providers,“ Microsoft Corporation, [Online]. Available: 8] http://msdn.microsoft.com/en-us/data/dd363565. [Zugriff am 12 6 2014]. [1 Microsoft Corporation, „Version History,“ Microsoft Corporation, 9] http://msdn.microsoft.com/en-us/data/jj574253.aspx. [Zugriff am 12 6 2014]. [Online]. Available: 69 Secure .NET Development [2 J. Meier, A. Mackman, B. Wastell und Prashant, „Protect From SQL Injection in ASP.NET,“ Microsoft 0] Corporation, 5 2005. [Online]. Available: http://msdn.microsoft.com/enus/library/ff648339.aspx#paght000002_step3. [Zugriff am 28 4 2014]. [2 OWASP Foundation, „Blind SQL Injection,“ OWASP Foundation, 26 8 2013. [Online]. Available: 1] https://www.owasp.org/index.php/Blind_SQL_Injection. [Zugriff am 3 5 2014]. [2 OWASP Foundation, „Insecure Direct Object Reference Prevention Cheat Sheet,“ OWASP 2] Foundation, 18 04 2010. [Online]. Available: https://www.owasp.org/index.php/Top_10_2007Insecure_Direct_Object_Reference. [Zugriff am 28 4 2014]. [2 E. Lippert, „GUID guide,“ Fabulous Adventures In Coding, 30 4 2012. [Online]. Available: 3] http://blogs.msdn.com/b/ericlippert/archive/2012/04/30/guid-guide-part-two.aspx. [Zugriff am 28 4 2014]. [2 OWASP Foundation, „Cross-Site Request Forgery (CSRF),“ OWASP Foundation, 9 11 2013. [Online]. 4] Available: https://www.owasp.org/index.php/CSRF. [Zugriff am 20 4 2014]. [2 W. Mike, „Preventing Cross-Site Request Forgery (CSRF) Attacks,“ Microsoft Corporation, 12 12 2012. 5] [Online]. Available: http://www.asp.net/web-api/overview/security/preventing-cross-site-requestforgery-(csrf)-attacks. [Zugriff am 4 5 2014]. [2 T. Dykstra, „Creating ASP.NET Web Projects in Visual Studio 2013,“ Microsoft Corporation, 9 9 2013. 6] [Online]. Available: http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visualstudio#auth. [Zugriff am 15 5 2014]. [2 H. Sun, „Understanding OWIN Forms authentication in MVC 5,“ Microsoft Corporation, 3 7 2013. 7] [Online]. Available: http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-formsauthentication-in-mvc-5.aspx. [Zugriff am 5 5 2014]. [2 Microsoft Corporation, „ASP.NET Web API,“ Microsoft Corporation, [Online]. 8] http://msdn.microsoft.com/en-us/library/hh833994(v=vs.108).aspx. [Zugriff am 9 6 2014]. Available: [2 M. Cretzman und T. Weeks, „Best Practices for Preventing DoS/Denial of Service Attacks,“ Microsoft 9] Corporation, [Online]. Available: http://technet.microsoft.com/en-us/library/cc750213.aspx. [Zugriff am 12 6 2014]. [3 Microsoft Corporation, „Open Data Protocol,“ 0] http://www.odata.org/. [Zugriff am 5 5 2014]. Microsoft Corporation, [Online]. Available: [3 H. Ge, „Protect your Queryable API with the validation feature in ASP.NET Web API OData,“ Microsoft 1] Corporation, 6 2 2013. [Online]. Available: http://blogs.msdn.com/b/webdev/archive/2013/02/06/protect-your-queryable-api-with-validationfeature-in-asp-net-web-api-odata.aspx. [Zugriff am 12 6 2014]. [3 J. Liberty und H. Alex, Programming .NET 3.5, Sebastopol: O'Reilly Media, Inc, 2008. 2] [3 D. Chappell, „Introducing Windows Communication Foundation,“ 1 2010. [Online]. Available: 3] http://download.microsoft.com/download/C/2/5/C2549372-D37D-4F55-939A74F1790D4963/Introducing_WCF_in_NET_Framework_4.pdf. [Zugriff am 12 5 2014]. [3 Microsoft Corporation, „WCF Essentials: Contracts,“ Microsoft Corporation, [Online]. Available: 4] http://msdn.microsoft.com/en-us/library/ff183866.aspx. [Zugriff am 12 6 2014]. [3 Microsoft Corporation, „How to: Use a Custom User Name and Password Validator,“ Microsoft 5] Corporation, [Online]. Available: http://msdn.microsoft.com/en-us/library/aa702565(v=vs.110).aspx. [Zugriff am 12 6 2014]. [3 Microsoft Corporation, „How to: Use the ASP.NET Membership Provider,“ Microsoft Corporation, 6] [Online]. Available: http://msdn.microsoft.com/en-us/library/ms731049(v=vs.110).aspx. [Zugriff am 12 6 2014]. 70 Secure .NET Development [3 Microsoft Corporation, „WCF and ASP.NET Web API,“ Microsoft Corporation, [Online]. Available: 7] http://msdn.microsoft.com/en-us/library/jj823172(v=vs.110).aspx. [Zugriff am 13 5 2014]. [3 Network Associates International BV., „Einführung in die Kryptographie,“ 24 12 1999. [Online]. 8] Available: ftp://ftp.pgpi.org/pub/pgp/6.5/docs/german/IntroToCrypto.pdf. [Zugriff am 6 5 2014]. [3 A. Beutelspacher, J. Schwenk und K.-D. Wolfenstetter, Moderne Verfahren der Kryptographie, 9] Wiesbaden: Vieweg+Teubner Verlag | Springer Fachmedien Wiesbaden GmbH 2010 , 2010. [4 Microsoft Corporation, „ECDiffieHellmanCng Class,“ Microsoft Corporation, [Online]. Available: 0] http://msdn.microsoft.com/en-us/library/system.security.cryptography.ecdiffiehellmancng.aspx. [Zugriff am 08 05 2014]. [4 Bundesamt für Sicherheit in der Informationstechnik, „Asymmetrische Verschlüsselung,“ Bundesamt 1] für Sicherheit in der Informationstechnik, [Online]. Available: https://www.bsi-fuerbuerger.de/BSIFB/DE/SicherheitImNetz/Verschluesseltkommunizieren/Grundlagenwissen/Asymmetri scheVerschluesselung/asymmetrische_verschluesselung_node.html. [Zugriff am 12 6 2014]. [4 F. Bourseau und D. Fox, „Vorzüge und Grenzen des RSA-Verfahrens,“ Datenschutz und 2] Datensicherheit, pp. 84-89, 2002. [4 GlobalSign, „PersonalSign-Zertifikate,“ GlobalSign, [Online]. Available: https://www.globalsign.com/de3] de/personalsign/. [Zugriff am 9 6 2014]. [4 K. K. Panday , „Various SSL/TLS Certificate File Types/Extensions,“ Microsoft Corporation, 4 11 2010. 4] [Online]. Available: http://blogs.msdn.com/b/kaushal/archive/2010/11/05/ssl-certificates.aspx. [Zugriff am 12 6 2014]. [4 D. Baier, „Unterstützen von Zertifikaten in Anwendungen mit .NET Framework 2.0,“ 3 2007. [Online]. 5] Available: http://msdn.microsoft.com/de-de/magazine/cc163454.aspx. [Zugriff am 10 5 2014]. [4 S. Tahiri, „Demystifying Dot NET Reverse Engineering,“ 24 10 2012. [Online]. Available: 6] http://resources.infosecinstitute.com/demystifying-dot-net-reverse-engineering-part-1-bigintroduction/. [Zugriff am 9 6 2014]. [4 T. Patton, „Reverse engineering your .NET applications,“ 17 5 2013. [Online]. Available: 7] http://www.techrepublic.com/blog/software-engineer/reverse-engineering-your-net-applications/. [Zugriff am 12 6 2014]. [4 G. Torok und B. Leach, „Thwart Reverse Engineering of Your Visual Basic .NET or C# Code,“ Microsoft 8] Corporation, 12 2003. [Online]. Available: http://msdn.microsoft.com/enus/magazine/cc164058.aspx#S3. [Zugriff am 12 6 2014]. [4 LogicNP Software, „8 Ways To Protect And Obfuscate Your .Net Code Against Reverse-Engineering 9] Using Crypto Obfuscator,“ LogicNP Software, [Online]. Available: http://www.ssware.com/articles/protect-and-obfuscate-your-dotnet-code-against-reverse-engineeringusing-crypto-obfuscator.htm. [Zugriff am 12 6 2014]. [5 Microsoft Corporation, „Overview of Protected Configuration,“ Microsoft Corporation, [Online]. 0] Available: http://msdn.microsoft.com/en-us/library/hh8x3tas(v=vs.100).aspx. [Zugriff am 12 6 2014]. [5 Microsoft Corporation, „Encrypting Configuration Information Using Protected Configuration,“ Microsoft 1] Corporation, [Online]. Available: http://msdn.microsoft.com/en-us/library/53tyfkaw(v=vs.100).aspx. [Zugriff am 17 5 2014]. [5 J. Roberts, „Protected Configuration,“ Blayd Software, 2] http://www.blayd.co.uk/article.aspx?pageid=1012. [Zugriff am 12 6 2014]. [Online]. Available: [5 Microsoft Corporation, „Importing and Exporting Protected Configuration RSA Key Containers,“ 3] Microsoft Corporation, [Online]. Available: http://msdn.microsoft.com/enus/library/yxw286t2(v=vs.100).aspx. [Zugriff am 12 6 2014]. [5 Microsoft Corporation, „Strong-Named Assemblies,“ Microsoft Corporation, [Online]. Available: 4] http://msdn.microsoft.com/en-us/library/wd40t7ad(v=vs.110).aspx. [Zugriff am 12 6 2014]. 71 Secure .NET Development [5 Microsoft Corporation, „Signierung mit starken Namen für verwaltete Anwendungen,“ Microsoft 5] Corporation, 11 2007. [Online]. Available: http://msdn.microsoft.com/dede/library/h4fa028b(v=vs.90).aspx. [Zugriff am 19 5 2014]. [5 Microsoft Corporation, „Übersicht über die ClickOnce-Bereitstellung,“ Microsoft Corporation, 11 2007. 6] [Online]. Available: http://msdn.microsoft.com/de-de/library/142dbbz4(v=vs.90).aspx. [Zugriff am 19 5 2014]. [5 S. Sanderson, „Prevent Cross-Site Request Forgery (CSRF) using ASP.NET MVC’s 7] AntiForgeryToken() helper,“ 1 9 2008. [Online]. Available: http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnetmvcs-antiforgerytoken-helper/. [Zugriff am 4 5 2014]. [5 S. Hongye, „Understanding OWIN Forms authentication in MVC 5,“ Microsoft Corporation, 7 3 2013. 8] [Online]. Available: http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-formsauthentication-in-mvc-5.aspx. [Zugriff am 28 05 2014]. [5 V. Raja und K. J. Fernandes, Reverse Engineering - An Industrial Perspective, London: Springer 9] Verlag, 2008. 72