Securitytests mit statischer Analyse 

 1. März 2015

In Anbetracht der zunehmenden Gefahr für die Sicherheit der IT-Anwendungssysteme wird von dem  Softwaretest erwartet, dass er einen Großteil der potentiellen Sicherheitslücken aufdeckt. Aber dynamisches Testen ist nicht die einzige Möglichkeit, Sicherheitsmängel im System zu entdecken. So kann die statische Analyse des Codes eine preisgünstige Methode darstellen, potentielle Sicherheitsgefahren aufzudecken. Dadurch können zwar nicht alle, aber ein Teil der potentiellen Sicherheitsmängel erkannt werden. (Hier verwendete Beispiele beziehen sich auf Java)

Zweck der statischen Analyse

Statische Analyse ist einer von vielen Testansätzen, um Mängel in einem Softwaresystem zu finden. Sie ist eine Technik für die Untersuchung der Anforderungstexte, Entwurfsmodelle und Code-Komponente die zu einem Softwareprodukt gehören, ohne das Produkt echt auszuführen 1. Design-Reviews und Code-Inspektionen basieren auf dem gleichen Prinzip, nur werden sie von Menschen durchgeführt. Eine statische Analyse wird von einem Automaten ausgeführt, der auf verschiedene Regeln prüft. Das Ziel ist Mängel in der Konstruktion der Software vor dem dynamischen Test aufzudecken 2.

Potentielle Sicherheitslücken im Code

Es stehen mittlerweile viele Werkzeuge für die statische Analyse von Source-Code zur Verfügung. Bei der Auswahl eines geeigneten Werkzeugs stellt sich die Frage nach den Mängelarten, die von dem Werkzeug berichtet werden. Eine weitere Frage ist die nach der Häufigkeit der Falschmeldungen, sogenannte “false positives”. Das sind Meldungen über Mängel, die in Wahrheit keine echten Mängel sind. Wenn Tools viele solcher Meldungen bringen, lenkt das nur von den echten Mängeln ab. Was die echten Mängel betrifft, ist es wichtig, ein Klassifikationsschema zu haben. Aus der Sicht der Codesicherheit gibt es fünf Hauptklassen von Mängeln: Fehlender Code, Unerlaubter Code, Manipulierbarer Code, Fehleranfälliger Code, Nicht-konformer Code 3.

Fehlender Code

Ein Beispiel von fehlendem Code ist die fehlende Kontrolle der Eingangsparameter von public Methoden. Als erstes wird geprüft ob die Eingangsdaten den richten Typ haben und ob sie im gültigen Wertebereich liegen. Wenn nicht, soll eine Ausnahmebedingung ausgelöst werden.

Das Gleiche gilt für Return-Ergebnisse. Werte die von aufgerufenen Methoden in entfernten Klassen zurückgegeben werden, sollten vor ihrer Verwendung kontrolliert werden.

Eine weiteres Beispiel für fehlenden Code ist das Fehlen der „final“ Klausel in einer Klassendefinition. Die Tatsache dass die folgende Klasse nicht mit „final“ deklariert ist, erlaubt es einem Eindringling, den Code zu kopieren und zu manipulieren. Um dies zu verhindern, sollten alle untergeordneten Klassen mit „final“ deklariert sein.

Mindestens ein Drittel des Codes sollte aus sicherheitsprüfenden Anweisungen bestehen. Ist dies nicht der Fall, ist das ein Zeichen dafür, dass die Ausführung des Codes nicht abgesichert ist 4.

Unerlaubter Code

Ein Beispiel für unerlaubten Code sind eingebaute Konstanten. Solche Werte im Code zu haben ist nicht wartungsfreundlich und gefährlich. Hacker die Zugriff zum Byte-Code gewinnen, können diese Werte verändern. Deshalb empfiehlt es sich, alle Konstanten in externe Ressourcen auszulagern. Dies gilt besonders für Texte 5.

Weitere Beispiele für Problemstellen sind Casts und Verschachtelungen.

Manipulierbarer Code

Ein Beispiel für manipulierbarem Code sind eingebaute SQL Anweisungen. Sie sind für SQL Injection Angriffe anfällig, womit Externe den Datenbankinhalt korrumpieren können. SQL Anweisungen haben im Anwendungscode somit nichts zu suchen. Wenn sie überhaupt verwendet werden, dann nur in einer geschützten Zugriffsschicht 6.

Weitere Beispiele für manipulierbaren Code finden sich in den Bereichen des Cloning und der Deserialisation.

Fehleranfälliger Code

Fehleranfälliger Code kann unter bestimmten Umständen leicht zu einem Fehler führen. Typisch für diese Art Mangel ist der Vergleich eines Objektes mit einem String oder eine Rekursion ohne Endbedingung. Was die Sicherheit anbetrifft, liegt eine potentielle Sicherheitslücke vor, wenn die Anzahl der Parameter beim Funktionsaufruf geringer ist als die Anzahl Parameter in der aufgerufenen Methode. In dem Fall hat der Eindringling die Möglichkeit, eigene Daten an die Parameterliste dranzuhängen und auf diese Weise Viren in den Code zu streuen 7.

Nicht-konformer Code

Nicht-konformer Code beinhaltet Abweichungen von einer vorgegebenen Norm. Dies ist zwar keine direkte Bedrohung für die Sicherheit, aber in manchen Fällen könnte es eine werden. Nehmen wir das Beispiel wenn bestimmte Standard-Services zu vermeiden sind, weil sie eventuell korrumpiert sind. Wer sie trotzdem in seinem Code anwendet, geht die Gefahr ein, dass er infizierte Objekte übernimmt.

Fallstudie zur Aufdeckung von Codemängeln

Eine Studie wurde an der North Carolina State University mit drei Millionen C++ Codezeilen von der Nortel Networks Corporation durchgeführt um zu zeigen, wie effektiv automatisierte statische Analyse sein kann 8. Mit dem Werkzeug “Flexlint” hat das Experiment mehr als 136.000 Mängel, bzw. einen Mangel pro 22 Codezeilen aufgedeckt und dass, obwohl der Code schon über drei Jahre im Betrieb war. Die Anzahl der Mängel aus der statischen Analyse korrelierte mit einer Genauigkeit von 83% mit der Anzahl der Fehlermeldungen aus dem PreRelease-Test. Dies spricht dafür, dass die Fehler genauso gut durch die statische Analyse hätten aufgedeckt werden können. Im Gegensatz zum dynamischen Test, der 12 Personenmonate kostete, hätte die statische Analyse nur 2 Personenmonate gekostet.

Erkennung von Sicherheitsmängeln in Java Code

Wie die Studie zeigt, kann die Mehrzahl der Mängel bereits im Code erkannt werden noch ehe getestet wird. Dies gilt ebenso für Sicherheitsmängel, nicht aber für andere nicht-funktionale Mängel wie z.B. Zeitverbrauch, Datenvolumen, Durchlaufkapazität 9. Werkzeuge, die bei der Prüfung unterstützen, können ohne großen Aufwand in den Entwicklungsprozess integriert werden (z.B. Continuous Integration). Im Zeitalter der agilen Entwicklung und der fortwährenden Auslieferung der Software müssen Mängel schnell und ohne großen Aufwand aufgedeckt und beseitigt werden. Dazu ist die statische Analyse des Codes das beste Mittel 10.

Folgende Liste soll beispielhaft zeigen, welche Regeln bei solchen Werkzeugen implementiert sind. Sie stammen aus dem Werkzeug JavAudit:

  • Vermeide die Allokation nicht-initialisierter Objekte
  • Beschränke den Zugang zu Klassen und Methoden
  • Finalisiere alle Klassen und Methoden
  • Verbiete das Hinzufügen neuer Klassen zu fertigen Paketen
  • Verbiete die Verschachtelung von Klassen
  • Erlaube keine Signatur – signing – des Codes
  • Packe den gesamten Code in einem einzigen Jar
  • Definiere alle Klassen als uncloneable
  • Definiere alle Klassen als unserializeable
  • Definiere alle Klassen als undeserializeable
  • Verbiete eingebettete SQL Anweisungen
  • Verbiete das Casting von Datentypen
  • Prüfe alle Eingangsargumente
  • Prüfe alle Return-Werte
  • Stelle alle IO-Operationen in try..catch Klammern
  • Stelle alle Aufrufe entfernter Methoden in try…catch Klammern
  • Vergleiche den Typ und die Anzahl Parameter in jeder Schnittstelle
  • Vermeide die Nutzung hard-codierter Datenwerte

Schlußfolgerung

Erfahrungen mit der statischen Code-Analyse zeigen, dass viele Sicherheitsmängel in einem IT System schon im Code sichtbar sind. Die statische Analyse ist ein preiswerter, schneller und zuverlässiger Weg, diese Sicherheitsmängel aufzudecken. Entwickler brauchen lediglich die richtigen Werkzeuge und den festen Willen, sauberen Code zu produzieren 11.

  1. Ayewah, N., Pugh, W., “Using Static Analysis to find Bugs”, IEEE Software Magazine, Sept. 2008, p. 22
  2. Chess, B.: “Improving Computer Security using extended Static Checking”, Proc. of IEEE Symposium on Security and Privacy, 2002
  3. Nagappan, N., Ball, T., “Static Analysis Tools as early Indicators of Prerelease Defect Density”, IEEE Proc. of Int.Conf. on S.E. (ICSE2005), p. 580
  4. Nakajo, T., “A Case History Analysis of Software Error Cause and Effect Relationships”, IEEE Trans. on S.E., Vol. 17, Nr. 8, August, 1991, S. 830
  5. Sneed, H. “Separating Hard-wired Data from Code”, in Proc. of CSMR2002, Budapest, March 2002, p. 64
  6. Merlo, E./ Letre, D./Antoniol, G.: “Automated Protection of Java Applications against SQL Injection Attacks”, IEEE Proc. of CSMR2007, Amsterdam, March 2007, p. 191
  7. Viega, J., McGraw, G., Felten, E.: “Statically Scanning Java Code – Finding Security Vulnerabilities”, IEEE Software Magazine, Sept. 2000, p. 68
  8. Zheng,, J.,Williams, L.,Nagappan, N., Snipes, W.: “On the Value of Static Analysis for Fault Detection in Software”, IEEE Trans. on S.E., Vol. 32, No. 4, April 2006, p. 240
  9. Lai, C., “Java Insecurity – accounting for Subtleties that can compromise Code”, IEEE Software Magazine, Jan. 2008, p. 13
  10. Zhang, M./ Hall, T./Baddoo, M.: “Code Smells – A Review of Current Knowledge”, Journal of Software Maintenance and Evolution, Vol. 23, N. 3, April 2011, p. 179
  11. Martin, R.: Clean Code – A Handbook of agile Software Craftsmanship, Prentice-Hall, Pearson Education Books, New Jersey, 2009