Mit der digitalen Transformation gelangen Geräte in den Fokus, die sonst eher unterhalb des Security-Radars laufen: Embedded-Systeme in Form von IoT-Devices. Das Internet of Things wird immer mehr zu einem unternehmenskritischen Teil der Infrastruktur. Geichzeitig sind die Sensoren und Aktoren im IoT schwierig gegen Angriffe und Missbrauch zu schützen. Sicherheit muss nach Einschätzung von Experten deswegen ein Designprinzip sein, das bereits bei der Entwicklung im Mittelpunkt steht.

Das Internet of Things (IoT) ist eines der prominentesten Beispiele dafür, wie die digitale Transformation Wirtschaft und Gesellschaft verändert. Zahllose Geräte vernetzen Unternehmen, Maschinen und Kunden. Das Marktforschungsunternehmen Gartner erwartet, dass die Zahl der IoT-Geräte in diesem Jahr weltweit auf über 14 Milliarden steigen wird. Bis 2021, so Gartner, werden 25 Milliarden Devices im IoT kommunizieren.

Die Geräte tauschen dabei zum Teil auch hochsensible Daten aus, etwa im medizinischen Bereich. Dabei sind die IoT-Geräte aus technischer Sicht zunächst einmal Clients, die über das Internet und andere Protokolle kommunizieren. Sie stellen also potenzielle Angriffsziele für Cyberkriminelle dar. Die Unternehmen haben das Problem erkannt: Laut dem Analystenhaus Juniper Research wächst der Markt für IoT-Security in den kommenden fünf Jahren um das Dreifache, die weltweiten Ausgaben werden 2023 über sechs Milliarden Dollar betragen.

In dem Rahmen, indem die Unternehmen die Kritikalität des IoT erkennen, nehmen Sicherheit und Zuverlässigkeit auch in der Softwareentwicklung einen immer größeren Stellenwert ein. Im Fall des IoT stehen besonders die Embedded-Systeme im Mittelpunkt. Denn im Gegensatz zu PC- und Server-Anwendungen lassen sich Embedded-Geräte nicht einfach über Updates und zusätzliche Sicherheitslösungen wie Malware-Scanner absichern. Dazu sind diese Geräte in der Regel zu schmalbandig an das Internet angebunden. Zudem ist die Hardware aus Kostengründen meist nicht gerade großzügig ausgelegt, freie Ressourcen sind eher die Ausnahme. Es gilt also, den Code bereits vor der Markteinführung so sicher und zuverlässig zu machen, dass das System kaum Angriffsfläche bietet. Dies ist nur mit mehrstufigen Konzepten bei der Qualitätssicherung zu schaffen.

Bei der statischen Analyse läuft der Code nicht ab, sondern es findet eine Überprüfung aller möglichen Zustände in einem Modell statt. Bild: Gramma Tech

Testing allein reicht nicht

Ein grundsätzliches Problem im Embedded-Segment ist die in der Regel genutzte Programmiersprache C/C++. Als C in den 70er-Jahren des vergangenen Jahrhunderts erstmals definiert wurde, lag der Fokus auf Geschwindigkeit und Flexibilität. Das Internet gab es nicht, Cybersicherheit war kein Thema. Mit C++ wurden die beiden größten, daraus resultierenden Probleme zwar entschärft, jedoch nicht aus der Welt geschaffen: Type-Sicherheit und ungeprüfte Pointer-Arithmetik. Besonders die Pointer-Arithmetik ist für viele Sicherheitsprobleme verantwortlich, die Wurzel der weit verbreiteten Buffer Overruns. Dazu kommt, dass die Definition, was ein korrektes C-Programm ist, der Flexibilität zuliebe sehr liberal ausfällt. Es gibt zahlreiche Doppeldeutigkeiten, die der Compiler interpretieren und auflösen muss.

Damit gelangt das übliche – und unverzichtbare – Testing an seine Grenzen: Ein Programm wird anhand definierter Testfälle auf Funktionalität und Fehlerfreiheit überprüft. Für die Suche nach klassischen Programmierfehlern, die zu Schwachstellen führen, ist das Testing indes nicht optimal geeignet. Die größte Herausforderung dabei ist, dass das Testing immer lauffähigen Code voraussetzt. Es kann also erst relativ spät innerhalb des Software Development Lifecycles (SDLC) zum Einsatz kommen. Dabei gilt: Je später ein Fehler entdeckt wird, desto aufwendiger ist seine Beseitigung. Zudem ist die Erkennung von Programmierfehlern im Testing grundsätzlich eingeschränkt. Denn Fehler werden nur gefunden, wenn die betreffende Code-Stelle vom Testfall durchlaufen wird, der Testfall an dieser Stelle zu einer Error-Condition führt und diese Error-Condition das erwartete Ergebnis des Testfalls beeinflusst.

Statische Analyse

Abhilfe kann die statische Code-Analyse schaffen. Im Gegensatz zum dynamischen Testing wird der Code bei der statischen Code-Analyse nicht ausgeführt. Tools wie CodeSonar von Gramma Tech erstellen aus dem Code vielmehr ein Modell, anhand dessen alle Steuerungs- und Datenströme durchlaufen und analysiert werden. Als Modell dient die Intermediate Representation (IR), wie sie auch Compiler erzeugen. Der Vorteil dieses Ansatzes ist, dass kein ausführbarer Code vorliegen muss. Die statische Code-Analyse kann also bereits in einer sehr frühen Phase des SDLCs zum Einsatz kommen. Da die statische Analyse alle Zustände berücksichtigt, die das Programm theoretisch einnehmen kann, lassen sich potenzielle Fehler mit deutlich höherer Trefferquote aufspüren. Zudem geben die Analyse-Tools den Entwicklern viele hilfreiche Informationen, die bei der Beseitigung der Fehler helfen. Programmierstandards in sicherheitskritischen Branchen, etwa DO-178 B/C in der Luftfahrt, schreiben daher den Einsatz dieses Verfahrens vor, viele andere Normen empfehlen es.

Die Visualisierung der Architektur gibt Aufschluss über Abhängigkeiten und Komplexität des Projekts und sorgt für eine bessere Übersicht. Bild: Gramma Tech

Zu den Fehlern, die im Fokus der Analyse stehen, gehören unter anderem die klassischen Einfallstore für Malware:

  • Buffer Overrun/Underrun,
  • Command Injection,
  • Integer Overflow of Allocation Size,
  • SQL Injection und
  • Non-constant Format String.

Eine zusätzliche Hürde bei der Qualitätssicherung stellt Code aus externen Quellen dar, der zunehmend auch im Embedded-Bereich zum Einsatz kommt. Komponenten wie Bibliotheken oder Kryptografie-Toolkits liegen häufig nur in binärer Form vor. Auch diese Komponenten sollte man auf Fehler und Schwachstellen hin überprüfen. Bei Binärcode ist dies nicht trivial, da dieser grundsätzlich anders aufgebaut ist als Quellcode: Binärer Code enthält zu wenig Struktur- und Debugging-Informationen, um in seinen Steuerungs- und Datenflüssen nachvollziehbar zu sein.
Dazu sind Tools unverzichtbar, die das Disassemblieren und Analysieren des Binärcodes anhand des daraus erzeugten Modells übernehmen. Das Ergebnis der Analyse im ersten Schritt nach dem Disassemblieren ist Assembler-Code, der nur theoretisch und mit immensem Aufwand von einem Entwickler gelesen werden kann. Eine Besonderheit bei CodeSonar von GrammaTech ist, dass dieser Assembler-Code mit Hilfe eines C-Decompilers in C-Code übersetzt werden kann, der für die Entwickler bei der Fehlersuche deutlich einfacher zugänglich ist. Zudem gibt das Tool dem Entwickler zahlreiche Hilfen, um gefundene Fehler genau zu lokalisieren und zu verstehen.

Mark Hermeling ist Senior Director Product Marketing bei Gramma Tech, www.grammatech.com.