Alle Beiträge von Marc Brown

Mit Standards zu besserer Software

Beinahe jede Branche hat Standards entwickelt, um über sichere und zuverlässige Software zu verfügen. Je kritischer der Einsatzbereich, desto strenger sind die Normen. Und desto größer ist der Aufwand, bis aus dem Entwicklungsprojekt ein marktreifes Produkt entsteht. Kritische Infrastrukturen, Flugzeuge, Automobile oder medizinische Geräte verlangen von den Entwicklern besondere Prozesse und Dokumentationen, bevor die Device in der Praxis eingesetzt werden darf. Je mehr Embedded Devices die Geschäftsmodelle und das Leben jedes Einzelnen bestimmen, desto wichtiger wird es auch außerhalb der hochkritischen Bereiche, eine hohe Software-Qualität sicherzustellen. In vielen Einzelbereichen kann die Überprüfung der Software auf Einhaltung der Normen und Standards automatisiert werden, etwa bei der Code-Analyse. Diese Möglichkeiten sollten genutzt werden, um Time-to-Market und Entwicklungskosten zu minimieren.

DO-178 C

CodeSonar erlaubt durch Visualisierung einen anderen Blick auf den Code, mit dem sich viele potenzielle Probleme frühzeitig erkennen lassen. (Quelle: Grammatech)

Mit die vielleicht strengsten Vorgaben hat die Avionik-Norm DO-178C (Software Considerations in Airborne Systems and Equipment Certification), die von EUROCAE komplett als ED-12C übernommen wurde. In Kapitel 6 befasst sich der Standard mit dem Verifizierungsprozess für Software. Einige der in den Kapiteln 6.3 und 6.4 aufgestellten Forderungen können mit geeigneten Tools wie GrammaTech CodeSonar weitgehend automatisiert und ohne große Aufwände überwacht werden. So etwa bei der unter Punkt 6.3.3 in DO-178 aufgestellten Forderung, dass sichergestellt sein muss, dass es keinen Konflikt zwischen der Software-Architektur und den High-Level-Anforderungen geben darf. Dabei werden besonders Funktionen wie Partitionierungsschemata hervorgehoben. Indem die Architektur durch das Analyse-Tool visualisiert wird, können die Entwickler interaktiv die Struktur der Software untersuchen. Die APIs von CodeSonar erlauben es zudem, automatisierte und individuell angepasste Checks zu integrieren.

Eine weitere Forderung in DO-178 ist, dass Partitionen isoliert sein müssen und Speicherlecks zu verhindern sind. Diese Anforderung sollte eigentlich in jedem Entwicklungsprojekt Standard sein. Um dieses auch zu gewährleisten, müssen sowohl der Daten- als auch der Control-Fluss exakt in allen möglichen Zuständen des Programms nachvollzogen werden. Unter anderem sollten sich dabei folgende Fragen beantworten lassen:

  • Können Daten aus Bereich A die Verarbeitung in Bereich B beeinflussen?
  • Gibt es einen Ausführungspfad zwischen Bereich C und Bereich D?
  • Welches sind die Caller der Funktion F?

Ein Analyse-Tool kann die Partitionssicherheit automatisch analysieren und zudem bei möglichen Problemen wichtige Lösungshinweise geben.

Neben diesen beiden Beispielen enthält die Avionik-Norm noch zahlreiche weitere Vorgaben, wie Software in einem hochkritischen Bereich sicher gestaltet werden kann. Für die meisten Entwicklungsprojekte ist es unsinnig, sich komplett an einem derart strengen Standard zu orientieren. Man sollte ihn vielmehr als Sammlung von Hinweisen betrachten: Welche davon auf das jeweilige Unternehmen und Entwicklungsprojekt passen, sollte im Vorfeld bereits evaluiert werden, um die Möglichkeiten zur Automatisierung bei der statischen Analyse optimal zu nutzen.

MISRA-C

Ganz ähnlich verhält es sich mit dem weit verbreiteten Standard MISRA-C, der aus dem Automotive-Bereich stammt und auch vor allem dort zum Einsatz kommt. Bei MISRA-C geht es weniger darum, Fehler zu verhindern, sondern um einen Regelsatz für die Entwicklung zur Verfügung zu stellen. Die Richtlinien befassen sich zum Beispiel mit dem Umgang mit Sprachkonstrukten, die nicht eindeutig definiert sind und so bei verschiedenen Compilern zu verschiedenen Ergebnissen führen können. Um die Einhaltung zu gewährleisten, setzt MISRA-C unter anderem den Einsatz von statischer Analyse voraus.

Einige der Regeln in MISRA-C sind im Rahmen einer automatischen Analyse einfach umzusetzen. Diese Regeln werden im Standard als „Decidable“ (Entscheidbar) bezeichnet, hier kann eine eindeutige Falsch/Richtig-Entscheidung getroffen werden. Das Verbot von Trigraphen, also der mit ?? beginnenden Drei-Zeichen-Ketten, gehört zu dieser Kategorie. Diesen Teil des Standards grundsätzlich in die eigene Entwicklung zu übernehmen, ist auf jeden Fall sinnvoll. Etwas komplexer wird es bei den als „System“ bezeichneten Regeln von MISRA-C, da hierbei mehrere Elemente des Codes gleichzeitig betrachtet werden müssen. Darunter fällt zum Beispiel die Forderung, das externe Identifier immer unterscheidbar sein müssen. Auch diese Regel ist zwar entscheidbar, aber nur, wenn das Analyse-Tool alle Code-Bereiche durchforstet und die gefundenen Identifier vergleicht. Manuell ist das kaum zu leisten, auch die Automatisierung dieser Prüfung gestaltet sich ziemlich schwierig. In der Praxis hat es sich als sehr effektiv erwiesen, das Analyse-Tool mit dem Build-System als vertrauenswürdige Quelle zu integrieren. Dann können auch diese Checks ohne größere Hürden in den eigenen Entwicklungsstandard übernommen werden.

Allerdings verfügt MISRA-C auch über Regeln, deren Einhaltung als „unentscheidbar“ bezeichnet wird. Es wird hierbei davon ausgegangen, dass es keine Methode gibt, die Einhaltung der jeweiligen Regel zu verifizieren oder zu falsifizieren. Das Verbot von direkten oder indirekten Rekursionen gehört in diese Kategorie. Um hierfür einen Checker zur automatischen Analyse zu entwickeln, muss man die Balance zwischen False Postives und False Negatives finden, um zu sinnvollen Ergebnissen zu gelangen. Hier gilt es, die einzelnen Regeln für die eigene Software-Entwicklung zu priorisieren. Denn nur sehr ausgereifte Analyse-Tools können hier wirkliche Hilfestellung bieten.

DIN EN 50128

Auch die DIN EN 50128 befasst sich mit der Entwicklung sicherer Software und kann, obwohl sie eigentlich für den Eisenbahnverkehr entwickelt wurde, in vielen Projekten Anregungen bieten. Die Norm ist im Kern eine Spezialversion der recht allgemeinen EN 61508. DIN EN 50128 bezieht sich zum Teil explizit auf MISRA-C und fordert neben Modularität komponenten-, struktur- und objektorientierte Programmierung. Der Einsatz eines Tools zur statischen Analyse ist explizit vorgesehen. Konkrete Forderungen umfassen zum Beispiel eine Begrenzung der Komplexität von Funktionen und Methoden, den Verzicht auf dynamische Variablen oder die Analyse von Steuer- und Datenfluss. Alle diese Faktoren können unter Verwendung von CodeSonar automatisiert abgebildet und somit relativ einfach in den eigenen Entwicklungsprozess integriert werden.

Die Fülle an Normen und Standards hat sicher ihre Berechtigung, doch verstellt sie auch gerne den Blick auf das Wesentliche: Allen Vorgaben gemein sind Best Practices, wie Software sicherer und zuverlässiger gemacht werden kann. Das ist zum einen im Interesse der Kunden und Anwender. Es ist aber auch im ureigensten Interesse der eigenen Unternehmen. Eine enge Anlehnung an diese Standards sorgt für transparente Prozesse, eine dokumentierte Vorgehensweise und klare, interne Regeln für die Entwicklung. Eine schnellere Time-to-Market, geringere Wartungsaufwände und Folgekosten sowie zufriedene Kunden sind der Lohn dieser Mühe.

Den Drittanbietern auf die Finger schauen

Software von Drittanbietern spielt bei der Entwicklung von Anwendungen eine immer größere Rolle. Experten gehen davon aus, dass heute bereits über 30 Prozent des Codes von Embedded-Applikationen aus den Händen von Zulieferern stammt. Meist handelt es sich dabei um spezielle Komponenten wie Grafik- und Windowing-Toolkits, Kryptografie-Bibliotheken oder Datenbanken. Diese Form des Outsourcings ist durchaus sinnvoll, die Entwickler können sich mehr auf die Kernfunktionen konzentrieren und so die Time to Market senken. Allerdings: Veröffentlicht ein Unternehmen Software mit Bestandteilen von Drittherstellern, übernimmt es gleichzeitig auch die Verantwortung für den gesamten Code.

Bei Open-Source-Komponenten ist das nicht weiter tragisch. Der Quellcode liegt vor, das Programm oder die Bibliothek kann mit den üblichen Test- und Analysemethoden geprüft werden. Ganz anders sieht es jedoch aus, wenn die Komponenten nur binär vorliegen. Diese können mit den meisten Analyse-Tools nicht überprüft werden. Somit bleibt nur das aufwändige Testing mit definierten Testfällen. Oder der Code bleibt ungeprüft. Blindes Vertrauen in den Drittanbieter birgt jedoch zahlreiche Risiken. Die Binärdateien können böswillige manipuliert werden, können einfach Programmierfehler enthalten oder die Binärdatei kann gefälscht sein. Leider kommen solche Dinge immer wieder vor, meist mit dem Ziel, die Hersteller der Software zu kompromittieren.

Fehlerquelle Compiler

Ein weiterer Grund, in der Entwicklung auch Binär-Code genauer unter die Lupe zu nehmen, sind die Compiler. Quellcode ist nicht der Code, der später im System tatsächlich ausgeführt wird. Die meisten Programmiersprachen sind in manchen Fällen ambig und inkonsistent. In solchen Fällen entscheidet der Compiler, wie der Code zu interpretieren ist. Das Ergebnis kann je nach eingesetztem Compiler deutlich variieren – mit weitreichenden Folgen. Ein prominentes und oft zitiertes Beispiel zeigte sich 2002 bei einem Sicherheits-Review bei Microsoft. Der Code

     {
         char password[MAXLEN];
         …
         memset(password,‘\0‘,len);
     }

 

wurde vom Compiler so interpretiert, dass auf den Speicherbereich nach memset nicht mehr zugegriffen wird und deswegen der memset() Call ignoriert werden kann. Das Ergebnis war, dass das Passwort im Klartext im Stack blieb.

Aufwändiger als Quellcode-Analyse

Auf die Analyse von Binär-Code zu verzichten, birgt also erhebliche Risiken. Ein Analyse-Tool, das sowohl Binär- als auch Quellcode statisch analysieren kann, ist CodeSonar von GrammaTech. CodeSonar ist in der Lage, sowohl ausführbare Dateien als auch binäre Bibliotheken auf Fehler und Schwachstellen zu prüfen. Dabei macht es keinen Unterschied, ob die Executables Symboltabellen und Debugging-Informationen enthalten (unstripped) oder nicht (stripped). Für viele Tools zur Analyse von Binärdateien stellen gestrippte Files eine große Hürde dar, CodeSonar kann auch aus diesen die relevanten Informationen gewinnen.

Binär-Code macht die Analyse einer Anwendung signifikant aufwändiger.

Und genau hierin liegt die Schwierigkeit bei der Analyse binärer Dateien: Viele der Informationen, die für eine statische Analyse notwendig sind, müssen erst aufwändig aus dem kompilierten Code generiert werden. Es sind also andere Analysemethoden gefordert als bei der Untersuchung von Quellcode. Auf der anderen Seite erzeugt die Analyse der Binaries auch Informationen, die sich aus den Quellen nicht ableiten lassen.

Einheitliches Modell

Das Tool erzeugt dazu ein Modell des gesamten Programms mit allen Source- und Binary-Bestandteilen: Was als Quellcode vorliegt, wird geparst und Binär-Code wird disassembliert. CodeSonar erzeugt daraus eine einheitliche Präsentation, die die Semantik beider Teile konsistent abbildet. Um mögliche Fehler zu erkennen, durchläuft das Werkzeug das Modell interprozedural und sucht nach Anomalien.

CodeSonar liefert den Entwicklern zahlreiche Informationen und Hinweise zur Fehlerbeseitigung.

Werden potenzielle Fehler gefunden, zeigt CodeSonar eine Warnung mit weiterführenden Hinweisen an. Im obenstehenden Screenshot entdeckte CodeSonar einen Buffer Overflow im Programm gnuchess. Alle relevanten Codebestandteile werden dabei automatisch markiert, eine detaillierte Meldung hilft bei der Fehlerbeseitigung. Wichtig sind diese Informationen nicht zuletzt deshalb, weil der erzeugte Assembler-Code kaum lesbar und völlig anders aufgebaut ist als ein Quellcode in einer modernen Programmiersprache. Binärcode kennt keine strukturierten Funktionen, somit lassen sich diese Hilfskonstrukte auch nicht beim Disassemblieren erzeugen. Man sieht nur, dass zum Beispiel die Funktion return_append_str ihren Platz in der Sektion _text hat und an die Adresse 0x419350 geladen wird. Eine manuelle Überprüfung dieses Codes wäre hier nicht nur sehr mühsam, sondern auch extrem fehleranfällig.

Schneller zu besserer Software

Der Einsatz von statischer Analyse bei Binär-Code hilft also dabei, eine hohe Software-Qualität auch dann sicherzustellen, wenn Komponenten Dritter in die Anwendung mit einfließen. Der Ansatz der statischen Analyse hat dabei einige Vorteile gegenüber anderen Methoden: Bei der statischen Analyse wird der Code nicht ausgeführt. Das Analyse-Tool ermittelt alle möglichen Zustände, die das Programm einnehmen kann. So können auch Fehler gefunden werden, die in definierten Test-Szenarien nicht auftreten. Durch die Möglichkeit, die Analyse zu automatisieren, skaliert das bei CodeSonar implementierte Verfahren auch für große und komplexe Software-Projekte. Für die Entwickler und für das Unternehmen bedeutet das: Sichere Software bei einer kürzeren Time to Market. Und gleichzeitig muss den externen Herstellern nicht mehr blind vertraut werden. Denn Vertrauen ist gut, Code-Analyse besser.

Wie verwundbar ist Ihre Software?

Wo beginnt man mit dem Einsatz statischer Analysetools im Rahmen von Security-Audits?

Wie bei jedem automatisierten Softwaretool ist es auch hier wichtig zu wissen, wonach man eigentlich sucht. Geht es um das Aufdecken der Sicherheitslücken in einem System ist ein Security-Audit sinnvoll. Hierzu müssen allerdings vorab einige manuelle Hausaufgaben gemacht werden: Sollte es zum Beispiel für das System keine formelle Bedrohungs-Analyse geben, ist es nun an der Zeit, eine solche durchzuführen, denn für ein Security-Audit ist es entscheidend, dass man über das Bedrohungsumfeld und die Angriffsoberflächen des eigenen Systems Bescheid weiß.

Bedrohungsmodell und Angriffsoberfläche

Die Wahrscheinlichkeit dafür, dass ein Gerät von einer Cyber-Attacke betroffen wird, hängt von den potenziellen Auswirkungen einer Attacke ebenso ab wie davon, ob eine solche Attacke möglich ist. Man nimmt nunmehr eine Beurteilung der Bedrohungslage vor, um ein Bedrohungsmodell zu erstellen und die Angriffsoberfläche zu ermitteln. Zu betrachten sind hierfür die Motivationen und Absichten potenzieller Angriffe ebenso wie die Wege, über die sie das System angreifen, und die Wahrscheinlichkeit für erfolgreiche Attacken:

  • Angriffsquellen und Motivationen – Insider, Aktivisten, Terroristen, Kriminelle, staatlich finanzierte Akteure oder auch Konkurrenten stellen potenzielle Bedrohungen dar. Kennt man die Quellen von Angriffen und ihre Motivationen, lässt sich leichter verstehen, welche Ziele eine Attacke haben kann, und ob eine solche Gruppe mit einem Angriff durchkommen könnte.
  • Rollen und Privilegien autorisierter Nutzer – Die Identifikation von Benutzern und ihren Zugriffsrechten ist entscheidend für die Durchsetzung des elementaren Least-Privilege-Prinzip Die Beschränkung der Zugriffsberechtigungen der betrieblichen Nutzer mit dem Ziel, gefährliche Verfahrensweisen oder das Hinausschleusen sensibler Daten zu unterbinden, hindert Insider und Angreifer am Zugang zu mehr, als ihnen gemäß ihren Zugriffsberechtigungen zusteht.
  • Identifikation potenzieller elektronischer Angriffsvektoren – Meist sind es Netzwerkverbindungen und andere I/O-Ressourcen, die Angreifern den Zugang eröffnen. In einigen Fällen kann der Angriffsvektor intern von einem lokalen Zugang zur Benutzeroberfläche oder einem lokalen Netzwerk ausgehen, während in anderen Situationen sogar der Zugriff per WAN oder Internet möglich sein kann.
  • Beurteilung der Schwierigkeit eines Angriffs – Aus der Verlustabschätzung lässt sich ersehen, welche Dienste und Funktionen von einer Attacke am meisten beeinträchtigt würden. Die relative Schwierigkeit dieser Angriffe muss auf der Grundlage der Angreifer und ihres Angriffsvektors beurteilt werden.
  • Zuweisung einer Bedrohungsmetrik – Jeden Angriff vorherzusehen, ist unmöglich. Ineffizient ist auch der Versuch, sich gegen jeden möglichen Angriff zu wappnen. Angriffen von außerhalb des zu verteidigenden Netzwerksegments etwa, die große Folgewirkungen hätten und einen geringen Schwierigkeitsgrad haben, würde eine hohe Bedrohungsmetrik zugewiesen. Jede Kombination aus Quelle und Motivation, Angriffsvektor und Schwierigkeitsgrad des Angriffs muss eine Bewertungsziffer erhalten.

 

Eine gründliche Bedrohungs-Analyse vermittelt ein Verständnis dafür, welche externen Schnittstellen die größten Angriffsrisiken bergen. Gleichzeitig macht diese Information deutlich, welche Schnittstellen und welche Arten von ‚Tainted Data‘ (vom Eingang) das Ausnutzen von Sicherheitslücken erlauben. Fortschrittliche statische Analysetools eignen sich insbesondere zum Aufdecken von Schwachstellen im Quellcode, darunter auch potenziell gefährliche Datenflüsse. Wenn man weiß, welche Schnittstellen analysiert werden müssen (z. B. das Netzwerk), lässt sich der Umfang der durchzuführenden Analyse bereits eingrenzen.

 

Die Konfiguration statischer Analysetools

Fortschrittliche statische Analysetools wie CodeSonar von GrammaTech bringen in ihrer Grundausstattung eine ganze Reihe von Warn- und Fehlermeldungen mit. Damit werden zwar die entscheidendsten und sinnvollsten Qualitäts- und Security-Defekte abgedeckt, die die Kunden benötigen, doch handelt es sich dabei nicht unbedingt immer um diejenigen Defekte, die für den Einzelfall am relevantesten sind. Bei der Durchführung frühzeitiger Security-Audits kommt es vielmehr auf das Eingrenzen der Analyse an, damit sich der Umfang der auszuwertenden Fehler- und Warnmeldungen auf ein sinnvolles Maß reduziert. Dies geschieht durch Anpassung der folgenden Parameter:

  • Warnungsklassen: Bei den meisten statischen Analysetools lassen sich Checker und Warnungen einzeln ein- und ausschalten. Da die Voreinstellungen für ein Security-Audit möglicherweise nicht ideal sind, wird empfohlen, die wichtigsten Fehlerklassen zu aktivieren, die weniger essenziellen Klassen dagegen zu beschränken.
  • Tainted-Data-Typen: Nicht alle Datenquellen sind potenzielle Angriffsvektoren oder in allen Systemen vorhanden. Zum Beispiel sind Netzwerk-Datenquellen bei vernetzten Geräten die Regel, während es Anwender- oder Dateieingaben nicht sind. Wichtig sind hier die Bedrohungsanalyse und die Angriffsoberfläche aus dem vorigen Schritt. Durch Beschneiden der analysierten Quellen reduziert man die Zahl der Falsch-Positivmeldungen und der Reports.
  • Uninteressanter Code: Subsysteme lassen sich so einschränken, dass unerwünschter Code aus der Analyse herausgehalten wird. Da die Tools die Intention der Software nicht verstehen, lässt sich durch manuelles Beschneiden des Codes die Analyse gezielt auf die wichtigen Abschnitte des Systems richten.
  • Abwägung zwischen Gründlichkeit und Zeitaufwand: Gelegentlich ist die Tiefe der Analyse einstellbar. Hier sollte für ein Security-Audit der höchstmögliche Wert gewählt werden. Es kommt darauf an, dass die Analyse so vollständig wie möglich ist, bevor hinsichtlich der aufgedeckten Schwachstellen irgendwelche Maßnahmen ergriffen werden.

Das Eingrenzen der Analyse auf die wichtigsten Schwachstellen ist wichtig, um einen ersten Überblick über die Sicherheitslage zu bekommen. Mit der Zeit lassen sich diese Parameter für ein umfassenderes Audit verändern, wie die folgende Grafik zeigt:

 

Grammatech
Grammatech

Auswertung der Ergebnisse

Mit den im vorigen Schritt konfigurierten, eingegrenzten Ergebnissen kann die eigentliche Analyse beginnen. Indem man die Resultate nach Priorität ordnet, lässt sich die Arbeit auf die wirklich kritischen Schwachstellen fokussieren. Zum Beispiel werden Pufferüberlauf-Fehler als kritischer angesehen als eine Warnung zum Programmierstil. Deshalb wird zu folgender Vorgehensweise geraten:

  • Priorisierung: Ordnen Sie die Fehler nach ihrer Priorität, bevor Sie ihre Gültigkeit analysieren. Es besteht die Möglichkeit, dass sich Falsch-Positiv-Meldungen in die Reports eingeschlichen haben. Um aber Zeit zu sparen, empfiehlt es sich zunächst die Fehler mit der höchsten Priorität zu analysieren. Möglicherweise bedürfen die Reports mit der geringsten Priorität gar keiner Überprüfung (sodass sie wahrscheinlich, wie oben beschrieben, komplett deaktiviert werden sollten).
  • Evaluierung: An dieser Stelle müssen die von den Tools gelieferten Reports in der Reihenfolge ihrer Priorität überprüft werden. Gravierende Fehler und der mit ihnen zusammenhängende Datenfluss sollten detailliert gecheckt werden. Die von Tools wie CodeSonar erzeugten detaillierten Reports helfen bei der Verifikation eines jeden Fehlers mit der Möglichkeit, sie jeweils als wahr oder falsch zu markieren und gegebenenfalls Bemerkungen anzufügen.
  • Kommentierung und Report: Die meisten fortschrittlichen statischen Analysetools liefern Reports zu jedem Analyselauf des Quellcodes. Sind die kritischen Schwachstellen validiert und kommentiert, ist der Security-Audit zum Quellcode fertig.
  • Ein fertiggestelltes Security-Audit kann für das weitere Risikomanagement, Abhilfemaßnahmen und Tests verwendet werden und lässt sich auch für die Gegenüberstellung mit Folgeversionen der Software nutzen. Es kommt darauf an, dass die statische Analyse zum Bestandteil eines iterativen Konzepts zur Verbesserung der Sicherheit wird.

Fazit

Statische Analysetools sind ein wirksames Hilfsmittel zur Verbesserung der Sicherheit. Die Einführung dieser Tools aber und die Festlegung eines Startpunkts für Ihr Team können zunächst schwierig erscheinen. Das Verstehen der Zielsetzungen ihres Security-Audits und Ihrer Bedrohungsbeurteilung kann bei der Einengung des Fokus helfen, wodurch die Analyseergebnisse an Relevanz und Nützlichkeit gewinnen. Durch Konfigurieren der Tools und Gliedern der Resultate nach Wichtigkeit wird der Audit-Prozess gestrafft, sodass er belastbare Ergebnisse hervorbringt.

Sicherheitskritische Software und die EN 50128 Norm

Die EN 50128 Norm  enthält klare Anforderungen an sichere Programmiertechniken, wie Modularität und komponenten-, struktur- und objektorientierte Programmierung. Zudem fordert sie den Einsatz von Modellierungs- und Programmierungsstandards sowie Sprachen-Subsets wie MISRA C. Für das Sicherheitsintegritätslevel (SIL) 3 und 4 sind diese Programmierungsstandards sogar obligatorisch. Hier bieten statische Analysetools wertvollen Support, denn sie eignen sich sehr gut zur Umsetzung strenger Codier-Standards, unabhängig davon ob es sich dabei um gängige wie MISRA C oder um kundenspezifische Versionen handelt.

 Tatsächlich schreibt die EN 50128 Norm die Nutzung statischer Analysetoolsunter Verwendung eines flexiblen Satzes von Programmierungsstandards, Steuerfluss- und Datenfluss-Analyseregeln vor, und empfiehlt sie dringend für SIL 1 bis 4. Interessanterweise heißt es in dieser Norm: „Nutzen Sie das inter-prozedurale Steuerflussanalyse-Modul, um eingesetzte Variablen vor deren Initialisierung, Pufferüberläufe, Speicherlecks usw. zu finden. Damit ist klar, dass die statische Analyse einen wichtigen Bestandteil jedes Instrumentariums für die Entwicklung sicherheitsrelevanter Software darstellt.

Grammatech
Grammatech

Die Tabelle veranschaulicht, wie spezifische Anforderungen von EN 50128  von statischen Analysetools erfüllt werden sowie ihren zugehörigen Empfehlungsgrad. Die Verweise beziehen sich auf einzelnen Klauseln in EN 50128.

Zusätzlich zur Konformität ist die Dokumentation zu ihrem Nachweis ein wichtiger Bestandteil der Erfüllung der Anforderungen von EN 50128. Automatisierte Softwaretools, einschließlich statischer Analyse, unterstützen den Zertifizierungsaufwand mithilfe von Berichtsfunktionen. Zusätzlich zu den weiteren Vorteilen wie Risikominimierung und einer kürzeren Entwicklungszeit erzielen sie eine schnellere Time-to-Market und Kosteneinsparungen.

Ein nach EN 50128 zertifiziertes Tool ist CodeSonar, dessen Funktionsumfang und Entwicklungsprozess von der SGS-TÜV Saar GmbH geprüft wurde, die auch bestätigt, dass es die Anforderungen für den Einsatz zur Entwicklung sicherheitsrelevanter Software erfüllt. Warum ist das wichtig? Werkzeuge zum Entwickeln von sicherheitsrelevanter Software müssen dokumentiert, und ihre Ergebnisse analysiert werden. Den Zertifizierungsvorgang mit zertifizierten Tools zu unterstützen verringert Risiko, Kosten und Zeit. Demgegenüber erfordern nicht zertifizierte Tools weitere Prüfungen durch die Zertifizierungsstellen – und führen gegebenenfalls zu höherem Aufwand und Risiko für das Entwicklungsteam.

Software in medizinischen Geräten

Der IEC 62304 Standard definiert keine spezifischen Entwicklungstools, dennoch unterstreicht er die Notwendigkeit von strengen Tests, Abnahmekriterien und Rückverfolgbarkeit. Diese Funktionen ohne Tools auszuführen, ist nicht sinnvoll im Hinblick auf den Umfang der meisten Projekte im Bereich Medizintechnik-Software. Beispielsweise verlangt der Abschnitt 5.5.2 von IEC 62304 eine Verifizierung jeder Software-Komponente, und der Abschnitt 5.5.4 fordert zusätzliche Abnahmekriterien dafür.

Der Hersteller soll bei der Programmierung zusätzliche Abnahmekriterien einbeziehen, wie

  1.  richtiger Ereignisablauf; 

  2.  Daten- und Flusskontrolle; 

  3.  Geplante Ressourcen-Zuteilung; 

  4.  Fehlerhandhabung (Fehlerdefinition, Isolation, und Wiederherstellung); 

  5.  Initialisierung der Variablen; 

  6.  Selbstdiagnose; 

  7.  Speicherverwaltung und Overflows; und 

  8.  Randbedingungen. 


Viele dieser Akzeptanzkriterien eignen sich gut für die statische Analyse. Tatsächlich trifft das sosehr für die statische Analyse zu, dass die FDA (Food and Drug Administration USA) CodeSonar von GrammaTech zur Analyse von Software für Medizingeräte einsetzte, um die Qualität des Quellcodes zu evaluieren, nachdem es zu Fehlfunktionen bei Infusionspumpen kam.

Unterstützt die Zertifizierung

Die statische Analyse bietet mehrere Vorteile für die Entwicklung von sicherheitskritischer Software, die auch für Medizingeräte und Projekte im Bereich IEC 62304 zutreffen. Zusammengefasst ergänzt sie die dynamische Analyse und strenge Tests auf mehrere Arten:

  • Sie findet Fehler, die anderen Testtechniken entgehen: Das Testen von Einheiten wird oft mit dem Abdeckungsgrad gemessen, wie Anweisungs- und Entscheidungsüberdeckung. Auch wenn dies genau ist, gibt es Fehler, die es durch diese Testart schaffen, und die statische Analysetools auffinden können.
  • Fehlerauffindung zu einem frühen Zeitpunkt: Fehler so zu verhindern, dass sie nicht später beim Entwickler aufschlagen, ist die Idealsituation – das erspart Aufwendungen für Tests und Behebung, die sich im weiteren Projektverlauf nur erhöhen. 
  • Statische Analyse kann SOUP handhaben: Software of Unknown Pedigree/Provenance (SOUP) bzw. Software unbekannter Herkunft erfordert spezielle Handhabung im Medizingeräte-Einsatz. Gute statische Analysetools können die Qualität und Sicherheit von Fremd- und kommerzieller Standard-Software (einschl. ausführbare reine Binärdateien und Libraries) evaluieren.
  • Schnellerer Zertifizierungsnachweis:  Die Dokumentation der Ergebnisse aus Zulassungen von Software-Komponenten ist entscheidend, um die Erfüllung von Zertifizierungsstandards nachzuweisen. Mit umfassenden Berichtsfunktionen unterstützt die statische Analyse die Zertifizierungsanforderungen.

Die Wichtigkeit von SOUP

Der Standard legt für SOUP (typischerweise 3rd-Party und kommerzielle Software) fest, wie diese in Medizingeräte-Software gehandhabt werden soll, beispielsweise in Abschnitt 7.1.2 (Teil des Risk-Management Prozesses) oder in Abschnitt B1.2 (Anwendungsbereich).

Statische Analysetools können sowohl Quell- als auch Binärcode analysieren und bieten Qualitäts- und Sicherheitsberichte, die in die Risk-Management und Test-Abläufe einfließen.

Auch wenn der IEC 62034 Standard nicht ausdrücklich statische Analysetools fordert, bieten diese sehr überzeugende Argumente für ihren Einsatz. Die Möglichkeit, Test- und Abnahmeprozesse zu unterstützen und zu verbessern, und die Analyse von SOUP bedeuten höhere Qualität, Sicherheit und Zuverlässigkeit für medizinische Software. 

 

Statische Analyse für IIot-Geräte

Für Industriegeräte gelten dieselben Herausforderungen wie für alle IoT-Geräte, u.a.  steigende Attraktivität für Hacker, traditionell vernachlässigte integrierte Sicherheit, breiter Einsatz von Altgeräten – bei zugleich höherer M2M Konnektivität und IoT-Hürde.  

Trotzdem sind IIoT-Geräte einzigartig:

  • Eingeschränkte Hardware in punkto Verarbeitungskapazität vieler moderner Sicherheitsfeatures wie Verschlüsselung, Network Stacks und eingebaute Firewalls.
  • Weil sie oft kritische Infrastruktur steuern, können sich mögliche Cyberangriffen viel schlimmer auswirken.
  • Industriesteuerungen und SCADA-Systeme haben andere Kommunikationsprotokolle und Standards als Heim- oder Bürogeräte.
  • Extrem langer Produktlebenszyklen und, verglichen mit anderen Geräten, schwierige Firmware- und Hardware-Updates, und andere Faktoren

Diese zusätzlichen Herausforderungen verschärfen das Thema Sicherheit für die Entwicklungsteams im Bereich IIoT.

Der vierstufige Verbesserungsprozess für IoT-Geräte gilt auch für IIoT, mit zusätzlichen Überlegungen. Die Übernahme der folgenden vier grundlegenden Schritte in einen Entwicklungsprozess für Embedded Software kann die Sicherheit (und Qualität) für hochvernetzte Geräte verbessern: 1) Design gemäß einer ‚Security-First‘ Philosophie, 2) wiederholte systemweite Einschätzungen und Analysen von Bedrohungen, 3) Wiedereinsatz von vorhandenen Tools so oft wie möglich, 4) Nutzung der modernen Quell- und Binärcodeanalyse, um die Qualität und Sicherheit von Fremdcode sicherzustellen.

Entscheidenden Support in den Codier- und  Integrationsphasen der Entwicklung bieten statische Analysetools wie Codesonar. Indem sie die dauerhafte Codequalität sowohl in der Entwicklungs- als auch Erhaltungsphase sicherstellen, reduzieren sie die Kosten und Risiken von Sicherheits- und Qualitätsproblemen ganz wesentlich. Speziell die statische Analyse eröffnet Vorteile wie folgt:

  • Dauerhafte Qualität und Sicherheit des Quellcodes
  • Auffinden und Prüfen von Tainted Daten
  • Prüfung der Qualität und Sicherheit von Fremdcode
  • Sichere Anwendung von Codierstandards

Als Teil einer ganzen Toolsuite bietet die statische Analyse wichtige Fähigkeiten, die anderen Tools fehlen. Sie amortisieren sich durch das frühe Auffinden von Fehlern und Schwachstellen, die gewöhnliche Testtools übersehen könnten. Das kommt der Sicherstellung von einem dauerhaft hohen Level an Qualität und Sicherheit zu Gute.

Befolgen Hersteller von M2M- und IIoT-Geräten eine ‚Security-First‘ Designphilosophie mit formeller Risikoeinschätzung und automatisierten Tools, sind ihre Geräte besser vor den steigenden Bedrohungen im Internet geschützt. Das Wichtigste ist die Erweiterung eines bestehenden erfolgreichen Software-Entwicklungsprozesses um Sicherheit zu einem frühen Zeitpunkt im Prozess. Mit dem intelligenten Einsatz von automatisierten Tools, um sowohl neuen Code zu entwickeln als auch bestehenden und Fremdcode zu sichern, können Entwicklungsteams straffe Budget- und Terminvorgaben einhalten. Die statische Analyse von Quell- und Binärcode spielt eine Schlüsselrolle in einem ‚Security-First‘ Entwicklungstoolset.

Separate Kompilierung von C++-Templates

C++-Templates sind ihrem Wesen nach so konzipiert, dass sie am besten funktionieren, wenn jeder Client das gesamte Template sieht – einschließlich der Prozedurrümpfe. Die Idee dahinter ist die, dass der Compiler entscheidet, welche Instanziierungen erfolgen müssen. Genau so werden die STL-Templates verwendet. Das kann jedoch eine hohe Last für den Compiler bedeuten, und die Kompilierung in bestimmten Situationen verlangsamen. Deshalb ist es mitunter von Vorteil, Template-Deklarationen und -Definitionen so zu organisieren, dass ihre separate Kompilierung möglich ist.

Bei GrammaTech begegnet uns diese Situation bei der Analyse von Maschinencode in unserem TSL-System. Für jede Architektur (z. B. IA32, PPC) generieren wir eine Template-Klasse, die Methoden enthält, die die Semantik dieser Architektur beschreiben. Diese Templates werden mit Analysespezifikationen instanziiert (z. B. use-def-Analyse, affine-relations-Analyse), um Implementierungen von use-def-Analysen für IA32, use-def-Analysen für PPC, affine-relations-Analysen für IA32, usw. zu erhalten. Wie Sie sich vorstellen können, sind diese Template-Klassen sehr umfangreich und enthalten ihrerseits sehr umfangreiche Methoden. Zudem müssen Analysen in der Lage sein, per Template-Spezialisierung einen Teil der Semantikklassenmethoden zu spezialisieren. Aus dem Wesen dieser Template ergeben sich zwei große Probleme:

(1) Wurden die großen KIassenmethoden-Definitionen in eine Header-Datei eingeschlossen, die jeder sieht, dauerte die Kompilierung sehr lange (hin und wieder ist es uns gelungen, den Compiler zu überlasten).

(2) Weil die Template-Spezialisierung eine schwierige Kunst ist, machten wir oft den Fehler, die Deklarationen nicht an die richtige Stelle zu setzen – ein Problem, das noch durch den Umstand verschärft wird, dass Compiler sich nicht beschweren, wenn Sie hier nicht sauber arbeitet, und dass unterschiedliche Compiler unterschiedlich reagieren, wenn man passiert, mitunter bizarr und unerwartet.

Zur Optimierung dieses Codes entwickelten wir ein Template (wenn man so will), um derartige Templates in einer Kollektion mit Header-Dateien zu organisieren. Das stellt  Abbildung 1 mit Pfeilen auf #include-Anweisungen dar. Zu beachten ist, dass es eine Regel gibt, die das Einschließen (#include) von cpp-Dateien untersagt – wenn also etwas von einer anderen Datei einzuschließen ist, auch wenn es wie eine cpp-Datei aussieht, muss es die Namenserweiterung „hpp“ erhalten. Diese Regel bedeutet auch, dass ausschließlich cpp-Dateien eine Kompilierungseinheit bilden.

Grammatech
Grammatech

Dieses Layout ist für den Fall vorgesehen, dass Methodenrümpfe (C) groß sind – etwa, wenn  die Anzahl der Kompilierungseinheiten, die diese sehen, minimiert werden soll – und für den Fall, dass es relativ wenige Instanziierungen (F) gibt. Bei diesem Layout werden die großen Methodenrümpfe in (C) nur einmal pro Instanziierung (F) kompiliert. Bei Templates im STL-Stil beispielsweise, wo die Anzahl der Instanziierungen in der Regel beliebig groß ist, würde dieses Layout nicht gut funktionieren, weil es die Erzeugung einer instantiator.cpp-Datei für jede Instanziierung erfordert (z. B. eine für set<int>, eine für set<unsigned int>, eine für set<foo>, … eine für jede Verwendung von „set“ im betreffenden Projekt).

Wichtig ist auch, dass gegebenenfalls mehrere Kopien von (C) und (F) möglich sind. Bei GrammaTech könnte Foo beispielsweise IA32Semantics sein, durch dessen viele große Methodenrümpfe die Kompilierung jedes Instantiators (F) ziemlich langsam erfolgt. Man  könnte (C) stattdessen in mehrere Dateien aufsplitten (z. B. eine pro Methode), und (F) entsprechend auch in mehrere Dateien aufteilen. Das Splitten von (F) könnte ein bisschen beschwerlich werden, weil die Template-Methoden einzeln instanziiert werden müssen. Es ist ein möglicher Kompromiss, um die Kompilierungszeiten zu verbessern.

Diese Gestaltung schließt Unterstützung für die Methodenspezialisierung (E) ein. Ihre Verwendung ist jedoch an Vorbehalte geknüpft. Wenn beispielsweise der Rumpf von func2 in (C) func1 aufruft, kann es erforderlich sein, dass (F) (E) einschließt, bevor (C) eingeschlossen wird – d. h., beim Kompilieren von func2 muss die Spezialisierung von func1 in (E) deklariert worden sein. In diesem Fall ist Folgendes zu berücksichtigen: Es bedeutet, dass die Inline-Methoden in (B) u. U. keine spezialisierten Methoden aufrufen – und der Template Designer ((A), (B), (C)) vorher nicht weiß, welche Methoden spezialisiert werden könnten. Um dem Rechnung zu tragen, könnte man das Bild durch Aufsplitten von (B) in zwei Dateien verfeinern – oder der Einfachheit halber Inline-Methoden einfach verbieten.

Leider lässt sich der sachgemäße Einsatz dieses „Templates“ nicht einfach mit einem Tool erzwingen oder validieren – das setzt Disziplin, profundes Wissen und Unfehlbarkeit voraus – Attribute, die – das müssen selbst die besten Programmierer einräumen – nicht zu garantieren sind. Dennoch hoffe ich, dass andere dieses Template hilfreich finden. Indes warte auf stabile Implementierungen der externen Templates von C++11, auch wenn ich nicht glaube, dass diese Gestaltung dadurch überflüssig wird.

Das ‚Human Internet of Things‘ (HIoT)

Freunde oder auch Fremde, die mich nach meiner beruflichen Tätigkeit fragen, können nur selten etwas mit den Fakten anfangen, von denen ich ihnen über unseren derzeitigen Stand bezüglich der Abwehr von Cyber-Bedrohungen berichte. Als ich stolz von unserem hervorragenden Abschneiden bei der Cyber Grand Challenge erzählte, zeigten sich die Menschen überrascht, dass es einer Maschine auch nur im Entferntesten möglich sein sollte, eine andere Maschine zu hacken, ohne dass ein Mensch dabei die niederen Arbeiten übernehmen muss. Natürlich kommen Unternehmen, die sich mit der Entwicklung von sicherheitskritischem Code befassen, mit den Cyber-Security-Risiken zurecht – aber wie steht es mit den einzelnen Menschen?

Der Durchschnittsbürger weiß möglicherweise nicht einmal, wofür das Kürzel ‚IoT‘ steht oder dass die Auswirkungen des IoT so enorm sind, dass wir bereits Teilbereiche wie das Industrial IoT (IIoT) schaffen mussten. Tatsache ist auch, dass sich GrammaTech auf Unternehmen und Organisationen konzentriert, und nicht auf einzelne Menschen. Wann aber wird das IoT die Menschen ganz persönlich betreffen? Wann werden wir die menschliche Version des IoT, also so etwas wie das ‚Human Internet of Things‘ haben?

Kürzlich fand mich auf einer Reise in der Warteschlange für einen Flug wieder, der in Halbstundenschritten immer mehr Verspätung ansammelte, ohne dass ein Ende in Sicht war. Als Grund wurde ein nicht näher benanntes ‚mechanisches Problem‘ angeführt, das zunächst behoben werden müsse. Langsam baute sich unter den Passagieren eine Missstimmung auf, als es hieß, der zuständige Techniker habe Probleme mit dem Installieren einer Software. Man sagte entschieden, man müsse nur noch das Softwareproblem herausfinden, und anschließend könnten wir los. Die Abflugzeit würde sich jetzt wirklich nur noch um weitere 25 Minuten verzögern.

Eigentlich eine interessante Situation –  mechanische Probleme, so dachten die Mitarbeiterin und vermutlich auch die anderen Passagiere, sind kompliziert und knifflig, und ihre Behebung nimmt viel Zeit in Anspruch, die wir nur in 30-Minuten-Schritten beziffern können. Die Lösung eines Softwareproblems dagegen wird höchstens 25 Minuten dauern.

Es kam wie es kommen musste: Nach den besagten 25 Minuten wurden wir an ein anderes Gate verwiesen und flogen mit einem ganz anderen Flugzeug. Anstatt aber von der Reise ermüdet und frustriert zu sein, fühlte ich mich auf seltsame Weise rehabilitiert.

„Software ist doch kompliziert!“ hätte ich am liebsten meinen ungeduldigen Mitreisenden zugerufen. „Und mit CodeSonar von GrammaTech können Sie Ihren Code besser verstehen!“

Natürlich hatten diese Menschen nichts mit Code zu tun, und so verlockend es auch sein mag, Moralpredigten zu halten – in diesem Fall wäre ich auf taube Ohren gestoßen. Doch dann sagte mein Nebenmann: „Ein Glück, dass es nur ein Softwareproblem war! Diese mechanischen Sachen haben mich schon langsam nervös gemacht!“ Daraufhin fragte ich mich, wann eigentlich die normalen Menschen besser über eines der größten Risiken für unsere Infrastrukturen, unsere Arbeitsplätze und unser Leben informiert werden müssen. Hätte ich die Auffassung meines Mitreisenden bestätigt, hätte ich damit implizit etwas Falsches als wahr durchgehen lassen?

Ich fragte mich nun, wie sehr normale Menschen eigentlich am Thema Cybersicherheit interessiert sind. Während die Passagiere unseres neuen Flugzeugs ausstiegen, stellte ich mit Google Trends auf meinem Laptop ein stetig wachsendes Interesse fest, was mich beruhigte: 

Grafik:
Grafik: Cyber Security

 

 

 

 

 

 

Trends sind aber eben doch nur Trends, und so benötigte ich einen Vergleich. Wie oft denken wir US-Bürger im Vergleich dazu an Donuts? Das Ergebnis war ernüchternd – mehr als 3/4 so viele!

Grafik:
Grafik: Donuts vs. Cyber Security

 

 

 

 

 

 

Bevor wir uns aber von Donuts ablenken lassen (hier gibt es ein enormes Potenzial), gehen wir lieber einen Schritt zurück und fragen uns: Muss sich der Normalbürger überhaupt um das Thema Cybersicherheit kümmern? Der normale Fluggast mag sich keine Gedanken um anfällige Software machen. Müssen wir uns aber unnötig die Köpfe schwermachen, solange sich die zuständigen Personen der Risiken bewusst sind?

Ich denke, dass unter anderem die folgenden Geschichten die Antwort auf diese Frage geben:

Mutter erfährt, dass die Webcam im Schlafzimmer ihrer Tochter gehackt war

Linux-Bug setzt 1,4 Milliarden Android-Nutzer der Gefahr von Hijacking-Attacken aus

So erschreckend einfach ist es, eine Verkehrsampel zu hacken!

Nach meiner Auffassung ist es nur eine Frage der Zeit, bis wir eine stärker individualisierte Variante des Internet of Things haben werden. Wenn ich auf einen Spam-verseuchten Link in einer Email klicke und sich daraufhin nicht mein, sondern Ihr Computer einen Virus einfängt, wer haftet dann für Ihren Schaden?

Wenn ein Hacker in mein Heimnetzwerk eindringt, meinen eigenen Computer unbehelligt lässt, stattdessen meine ganze Stadt infiltriert und dabei auf einen wichtigen Computer zugreift, der entscheidende Infrastrukturen kontrolliert – was passiert in diesem Fall, wenn eine Schwachstelle ausgenutzt wird, und die Stromversorgung der gesamten Stadt zusammenbricht? Wird man den Vorfall bis zu meinem Heimnetzwerk zurückverfolgen, das der Neffe meiner Schwägerin eingerichtet hat, weil er sich ‚damit auskennt‘?

GrammaTech ist in der Tat ein Unternehmen, das Probleme für Organisationen auf der ganzen Welt löst, die die Sicherheit ihrer Kunden schützen. Wie aber wird es sein, wenn wir nicht mehr diese Organisationen als Mittelsmänner haben, sondern wenn wir selbst mehr Verantwortung für unsere Sicherheit übernehmen? Wann wird es endlich das Human Internet of Things geben? ich glaube, ist es nur eine Frage der Zeit.