Kategorien: Unternehmen
Entwicklung sicherer Software
Software enthält Fehler. Das gehört leider zu den unabänderlichen Tatsachen in der Softwareentwicklung. Das heißt jedoch noch nicht, dass wir nicht etwas dagegen tun können, dass Fehler entstehen, versuchen können, die Auswirkung von Fehlern zu begrenzen, oder daran arbeiten können, wie wir auf Fehler, die wir finden, reagieren.
Im ersten Abschnitt werfen wir einen Blick auf die Ausgangslage. Auch wenn es unmöglich ist, zu sagen, wie viele unentdeckte Fehler existieren, so gibt es doch Abschätzungen, die einen ganz guten Anhaltspunkt geben können. Im zweiten Abschnitt geben wir einen Überblick über eine Auswahl an Maßnahmen, die wir treffen, um Fehler zu vermeiden. Im dritten Abschnitt beleuchten wir den reaktiven Teil des Schwachstellenmanagements.
Ausgangslage
Um zu verstehen, wie wir möglichst viele Fehler vermeiden und ideal auf die verbleibenden Fehler reagieren können, müssen wir die Art der Fehler und ihre Häufigkeit kennen und wissen, wo sie üblicherweise auftreten.
Für die Frage, wie viele Fehler sich statistisch in tausend Zeilen Code verbergen, wird gerne die Statistik aus Steve McConnells Buch „Code Complete“ herangezogen. Wenn wir hier die Ausnahmen ausklammern, liegt die Statistik zwischen 10 und 50 Fehlern in 1000 Zeilen Code. Das bedeutet, dass wir statistisch in jeder zwanzigsten bis hundertsten Zeile, die wir schreiben, einen Fehler machen, den der Compiler nicht sofort findet. Das ist beeindruckend oft und uns sollte überraschen, dass unsere IT-Systeme selbst mit dieser Menge an Fehlern so zuverlässig funktionieren.
Es ist jedoch nicht nur die Häufigkeit der Fehler, sondern auch die Art der Fehler entscheidend. Da wir uns in diesem Artikel der Entwicklung sicherer Software widmen, setzen wir den Fokus auf zwei Fehlertypen: Bugs und Flaws. Unter Bugs verstehen wir klassische Programmierfehler. Flaws sind Fehler in den Designentscheidungen. Um Bugs zu finden, gibt es inzwischen einen großen Werkzeugkasten, der dabei hilft, den Code nach unterschiedlichsten Fehlerklassen zu durchsuchen. Darauf gehen wir im Abschnitt „Präventive Maßnahmen“ etwas genauer ein. Flaws hingegen sind oft schwer zu finden, da hier im Design und in der Entwicklung oftmals implizite Annahmen getroffen werden, die nicht oder nicht mehr gültig sind und somit zu Schwachstellen in der Software führen, die eventuell für einen Angreifer ausnutzbar sind.
Das ist das Stichwort für die nächste präventive Maßnahme: Wir müssen dafür sorgen, dass Fehler nicht zu ausnutzbaren Fehlern werden. Denn nicht jeder Fehler ist für einen Angreifer ausnutzbar. Wenn wir die Strukturen verstehen, die wir nutzen können, um zu verhindern, dass ein Angreifer einen Fehler in der Software nutzen kann, können wir einerseits dafür sorgen, dass potenzielle Fehler in der Entwicklung nicht zu Schwachstellen in den Produkten führen und andererseits können wir besser verstehen, ob ein Bug, den wir finden, zu einer ausnutzbaren Schwachstelle führt. Wir benötigen also sowohl für die Analyse als auch für die Planung neuer Entwicklungen ein Verständnis für die Auswirkungen potenzieller Fehler.
Präventive Maßnahmen
Softwarearchitektur
Die Basis einer Software ist eine gründliche Anforderungsanalyse. Alle Ergebnisse der Anforderungsanalyse fließen in die Konzeption der Softwarearchitektur ein, die aus fachlicher und technischer Sicht modelliert wird. Der Entwurf entsteht in der Zusammenarbeit erfahrener Softwareentwickler und -architekten, die vom International Software Architecture Qualification Board (iSAQB®) zertifiziert sind, und einem produktunabhängigen Team von Sicherheitsexperten, das das Konzept von der Architektur bis hin zur Verwendung kryptografischer Primitive auf Herz und Nieren prüft.
Coden & Testen
Wenn das Produkt den Entwürfen entsprechend entwickelt wird, stützen wir uns auf eine Reihe von Technologien, um Fehler im Code möglichst früh zu identifizieren und zu beheben. Zum Standard in allen Firmen gehört hierzu inzwischen ein Versionsverwaltungssystem (Wibu-Systems setzt hierbei auf Git), das das Vier-Augen-Prinzip erzwingt. Keinem Entwickler ist es möglich, Code ungesehen und ungeprüft in ein Produktrelease zu bringen.
Mittels SonarLint erfolgt eine statische Codeanalyse innerhalb der Entwicklungsumgebung. Zur kontinuierlichen statischen Codeanalyse des Quellcodes und zum kontinuierlichen Testen der technischen Softwarequalität setzen wir die kommerzielle Version von SonarQube auf unserem Build-Server ein. SonarQube deckt mehr als 5.000 statische Analyseregeln (MISRAC, CERT C/C++) ab und hilft dabei, wirklich sauberen Code zu schreiben. Compilerwarnungen und Ergebnisse der statischen Codeanalyse sind nach jedem Build verfügbar.
Die Überprüfung der Korrektheit der Anwendung zur Laufzeit wird von der dynamischen Codeanalyse übernommen. Dank Fuzzing werden viele Eingaben simuliert. Allein dadurch werden viele Sicherheitslücken von Hackern entdeckt, denen wir somit zuvorkommen. Eingesetzt werden unter anderem die Tools Radamsa, LibFuzzer, AFL, WinAFL sowie GCC, ASAN, UBSAN und Valgrind.
Für neue Implementierungen werden Unit-Tests entwickelt, damit wir Regressionen unter Kontrolle haben. Für Fehlerbehebungen passen wir Unit-Tests, aber auch die automatischen Integrationstests an. Wir haben das Konfigurationsmanagement und die Orchestrierung dank Ansible und Terraform unter Kontrolle. Insgesamt benötigen wir eine umfangreiche Infrastruktur zum Entwickeln und Testen, die als Code gehandhabt wird.
Unsere Build- und Testprozesse sind mit Jenkins und mit GitLab Runner automatisiert und wir erstellen jede Nacht einen Build, um die Ergebnisse der nächtlichen Tests unter verschiedenen Betriebssystemen in verschiedenen Anwendungsfällen am nächsten Arbeitstag zu haben. Werden bei den automatischen Tests Fehler entdeckt, werden die Fehlerursachen untersucht und die Probleme behoben. Sicherheitsrelevante Fehler erhalten unabhängig davon, wie sie gefunden wurden, ein entsprechendes Flag. Das stellt sicher, dass sie die höchste Aufmerksamkeit erhalten.
Sichere Produkte können nur von Softwareentwicklern produziert werden, die in der Lage sind, sicheren Code zu schreiben. Durch regelmäßige Schulungen zu Sicherheitsthemen wie den OWASP Top 10, Best Practices in bestimmten Programmiersprachen, Betriebssystemen und Containern, Fuzzing und vielem mehr lernen Entwickler, wie sie typische Sicherheitslücken im Code vermeiden können. Durch obligatorische Schulungen im Rahmen des Onboarding-Prozesses für neue Mitarbeiter stellen wir sicher, dass IT-Sicherheit und Sicherheitsbewusstsein nicht zu kurz kommen. Die regelmäßigen Schulungen zu verschiedenen Sicherheitsthemen werden sowohl intern als auch extern durchgeführt. Um die Verfügbarkeitsschwelle zu verringern und Nachverfolgung der Schulungsteilnehmer zu erleichtern, haben wir eine interne Wibu Academy eingeführt.
Third Party Software
Zum Alltag jedes Softwareentwicklers gehört, dass Funktionalitäten nicht selbst entwickelt werden, sondern durch Bibliotheken erbracht werden, die von anderen Entwicklern stammen. Eine schlechte Auswahl dieser Bibliotheken kann die Sicherheit der Software gefährden. Auch Angreifer machen sich dies gerne zu Nutze und greifen nicht das Unternehmen, sondern seine Zulieferer an. Solcher Angriffe, auch Supply-Chain-Attacks genannt, ist sich Wibu-Systems bewusst und schützt seine Kunden durch eine gezielte Reduktion der Abhängigkeiten und der sorgfältigen Auswahl und eines engmaschigen Monitorings der übrig bleibenden Komponenten. Als besonders gefährlich erachten wir Build-Prozesse, die zum Build-Zeitpunkt die aktuelle Version aus dem Repository des Anbieters laden. Zwar wird dann die aktuelle Version mit allen Sicherheitspatches verwendet; es besteht jedoch das Risiko, dass auch der noch unentdeckte Schadcode eines Angreifers integriert wird. Aus diesem Grund werden unsere Build-Systeme so entworfen, dass sie keinen Onlinezugang benötigen und demzufolge auch nicht haben.
Operation
Wibu-Systems bietet neben Produkten auch Services an. Einige Produkte hosten wir für unsere Kunden. Die bei Wibu-Systems gehosteten Dienste werden permanent überwacht und gewartet, ebenso wie das Betriebssystem.
Reaktive Maßnahmen
Durch all diese Maßnahmen sollte es doch möglich sein, Fehler auszuschließen. Wir wissen, dass wir den Zustand heute noch nicht erreicht haben, und die Autoren dieses Artikels glauben auch nicht daran, dass Fehler grundsätzlich ausgeschlossen werden können. Sie erinnern sich daran, dass ein Fehler in der Definition ebenfalls zu einer Schwachstelle führen kann, die so nicht vorhergesehen wurde? Richtig, wer könnte Log4Shell so schnell vergessen? Was da schiefgelaufen ist, müssen wir hier nicht erneut diskutieren.
Wenn wir nicht alle Fehler ausschließen können, müssen wir uns also damit beschäftigen, wie wir mit Fehlern umgehen. Der erste und wichtigste Aspekt ist, dass wir akzeptieren, dass Software Fehler enthält: die Software, die wir selbst entwickeln, und die Software, die wir von anderen Herstellern beziehen und einsetzen. Es geht weniger darum, ob ein Fehler gefunden wurde, sondern wie damit umgegangen wird. Unter der Annahme, dass Schwachstellen nicht absichtlich oder leichtsinnig in die Software gelangt sind, gibt es keinen Grund für Ärger oder Unhöflichkeit.
Ist der Fehler in der Software anderer Hersteller wünschen wir uns drei Dinge: Erstens, dass wir möglichst schnell und einfach eine Version ohne den Fehler erhalten, um uns und unsere Kunden vor Angriffen schützen zu können. Zweitens, dass wir als Betroffene möglichst viele Informationen über die möglichen Auswirkungen erhalten, damit wir selbst beurteilen können, wie wir mit dem Fehler umgehen wollen und müssen. Drittens, dass wir stets über den aktuellen Stand informiert werden.
Wie sieht jedoch die andere Seite aus? Um einen möglichst guten Support für den Kunden zu ermöglichen, bedarf es einiger Struktur in der Firma, in deren Software die Schwachstelle gefunden wurde. Das beginnt bei einer Stelle, an der Kunden gefundene Schwachstellen melden können, geht über ein Team, das die Behandlung größerer Schwachstellen koordiniert (CERT), und die Etablierung fester Kommunikationsstrukturen innerhalb der Firma mit Ansprechpartnern in jedem Produkt, bis hin zu einer guten Koordination der Kommunikation zum Kunden.
Jeder dieser Aspekte verdient das gleiche Maß an Aufmerksamkeit. Und mit Details zu jedem dieser Aspekte lassen sich ganze Bücher füllen – oder für einen Überblick zumindest einen ganzen Artikel. Das haben wir auch bereits getan: Einen ausführlicheren Bericht über die reaktive Seite haben wir bereits letztes Jahr in der KEYnote 43 beschrieben.
KEYnote 46 – Ausgabe Herbst/Winter 2023