20. Februar 2020 von Oliver Kling
Application Security in modernen Microservices-Architekturen
Security Frameworks gewinnen an Bedeutung
Ein nicht ganz neuer Trend setzt sich auch in Microservices-Architekturen fort: Frameworks, Libraries und Infrastrukturschichten (zum Beispiel die Container-Funktionalitäten im Linux-Kernel) übernehmen Sicherheitsfunktionen, die bisher teilweise durch die Anwendungsentwicklung zu implementieren waren.
Anstelle von längeren und selbstentwickelten Code-Strecken, werden in modernen Umgebungen zunehmend Sicherheitsfeatures durch Konfiguration vermehrt oder, wie bei Spring-Boot, durch Dependency-Management-Lösungen ersetzt. Das hat den großen Vorteil, dass sicherheitskritische Teile des Codes wiederverwendet werden können. Außerdem profitiert das Entwicklungsteam von den Erfahrungen und Verbesserungen in diesen Frameworks. Die Gefahr von Fehlern reduziert sich dabei zum Teil auf eine korrekte Verwendung. Klassische Implementierungsrisiken können somit besser vermieden werden. Ein wenig folgt diese Idee dabei dem Prinzip von Kerkhoff, das besagt, dass kryptographische Funktionen nicht selbst designt und implementiert werden sollten. Die entsprechende Abstraktion gilt dann natürlich auch für weitere Themen - etwa für die Authentifizierung oder für das Berechtigungsmanagement.
Dieser Trend bringt aber auch gewisse Nachteile mit sich – Stichwort: „There is no free lunch“:
Erstens entbindet dies ein Entwicklungsteam nicht davon, genau zu verstehen, welche Funktionalitäten an welcher Stelle im Stack zu implementieren beziehungsweise zu konfigurieren sind. Man tauscht dabei quasi das Wissen über eine sichere Programmierung mit Kenntnissen über die verwendeten Frameworks aus. Eine erste Einschätzung, dass damit das notwendige Security Know-how nicht kleiner wird, ist sicher nicht völlig falsch.
Zweitens bringt die Delegation und Verwendung vieler Libraries und Komponenten eine massive Erhöhung der Komplexität mit sich, die nicht immer ein Gewinn an Security bedeutet. Es wird dann zu einer große Herausforderung, eine zielführende Analyse durchzuführen. Auch wenn ihr im Hinblick auf Security gerne nur notwendigen, klar strukturierten und übersichtlichen Code hättet, hilft es nicht, sich gegen diesen generellen Trend zu wehren.
Security-Fachleute stehen bezüglich der Migration von Sicherheitsfunktionen ähnlichen Anforderungen wie Entwicklerinnen und Entwickler gegenüber, die häufig „nur noch“ sogenannten Glue-Code schreiben, der Frameworks, Services und Libraries sinnvoll miteinander verbindet. Kenntnisse über Libraries werden nun auch für Security-Expertinnen und Experten zwingend notwendig. Potenziell ist das eine Abwägung zwischen weniger Security-Schwachstellen im eigenen Code und einem besseren Verständnis der Frameworks. Kritisch ist es, die Fähigkeit bewerten zu können und die Frage zu beantworten, wo und wie Security am besten zu implementieren ist.
Security in stark verteilten Systemen
In Microservices-Architekturen, die per Definition verteilt sind (Zugriff über Netzwerk-Protokolle), entsteht erstmal eine potenzielle Vergrößerung der Angriffsoberfläche (Attack-Surface). Funktionen, die früher als interne Funktionen implementiert waren, sind plötzlich - zunächst nur theoretisch - von anderen Anwendungen aus angreifbar. Der Security-Vertrauensbereich verengt sich auf den eigenen Service. In diesem Kontext stellen sich verstärkt Fragen zur Authentifizierung von Services untereinander sowie zur Kontrolle von Berechtigungen über Services hinweg.
Es ist nicht so, dass die Softwareentwicklung vor ungelösten Problemen stehen würde, allerdings steigt natürlich insgesamt die Komplexität. Schließlich muss prinzipiell jeder Service eigenständige Sicherheitsentscheidungen treffen. Ein einfaches Beispiel ist der Aufruf eines Microservices „A“ durch einen Benutzer über ein User Interface. „A“ benötigt wiederum verschiedene Services - etwa „B“, „C“ und „D“ - für die Erledigung der ursprünglichen Aufgabe. Die Services „B“, „C“ und „D“ sollten jedoch in der Lage sein, selbst zu entscheiden, inwieweit der ursprüngliche Benutzer die Berechtigung hat, um etwa bestimmte Daten zu sehen oder zu ändern. Dem Service „A“ alle Rechte auf die Services „B“, „C“ und „D“ zu geben, ist natürlich keine besonders gute Idee. Werden Security-Tokens genutzt, ist beispielsweise ein Token-Wechsel erforderlich, der sicherstellt, dass Service „A“ mit den Berechtigungen des Endbenutzers den Service „B“ aufruft. Dies führt fast logischerweise zu einer Erhöhung der Komplexität beziehungsweise es hat eventuell unerwünschte Nebenwirkungen auf die Performance oder das Gesamtantwortzeitverhalten.
Der Kreis schließt sich ein wenig, wenn ihr bei Microservices entsprechende Infrastrukturen verwendet. Diese sollten ihrerseits Maßnahmen anbieten, um einzelne Services erreichbar beziehungsweise verfügbar zu machen - zum Beispiel nur innerhalb eines Cluster (etwa Kubernetes). Auch hier bedarf es jedoch guter Kenntnisse der Infrastruktur und deren Möglichkeiten.
Fazit
Es ist der Trend zu beobachten, dass Security-Funktionalitäten mehr und mehr „in den Stack“ wandern. Das führt zu einem notwendigerweise erhöhten Bedarf an Kenntnissen über eben diesen Stack.
Die größere Verteilung von Funktionen über das Netzwerk stellt eine eigentlich bekannte Herausforderung erneut in den Fokus. Sichere Lösungen beruhen auch hier wieder auf einem sauberen Zusammenspiel zwischen der Anwendung und der unterliegenden Infrastruktur. Damit werden Application Security Engineers stärker in die IT- und Infrastruktursicherheit eingebunden, wobei eine strikte Trennung zwischen Anwendungs-Code und Infrastruktur auch bisher weder sinnvoll noch möglich war.
Ihr möchtet mehr zum Thema Application Security erfahren, dann werft auch einen Blick in meinen bereits erschienenen Beitrag zum Thema Application Security in einer agilen Welt.
Weitere spannende Themen aus der adesso-Welt findet ihr übrigens in unseren anderen Blog-Beiträgen.