Die sichere Programmierung von Anwendungen ist nicht erst durch neue Normen wie die ISO/IEC 27002 ein zentrales Gut von Unternehmen. Die Stichwortsuche „secure coding“ erzielt bei der Google-Suche 180.000.000 Treffer, entsprechend gibt es unzählige Berichte, Anleitungen und Grundsätze zu diesem Thema. Ein Grund mehr, sich mit der sicheren Entwicklung ausgiebig zu beschäftigen. Die ISO/IEC 27002 Norm wurde 2022 in einer neuen Version veröffentlich (siehe auch Blogbeitrag „Die neue ISO/IEC 27002“). Im Laufe dieser Blogreihe soll allen Interessierten ein erster Einblick in die neuen Maßnahmen (Controls) aus der neuen 27002:2022 ermöglicht werden. In diesem Beitrag stellen wir Ihnen das Control „8.28 Secure coding“ vor.
Warum sichere Programmierung ein wichtiges Gut ist
Zum Verständnis von sicherer Programmierung genügt häufig ein Blick darauf, was passiert, wenn die ausgelieferte Software Fehler enthält. Es gibt unzählige Softwareprojekte auf der Welt und keines davon wird fehlerfrei sein. Dennoch bietet es sich an, die fahrlässigen Fehler von vornherein zu vermeiden und sich dazu an einige Grundsätze der sicheren Programmierung zu halten. Fahrlässig meint in diesem Kontext Fehler bzw. gängige Sicherheitslücken zu begehen, welche bereits durch Generationen von Entwicklern gemacht wurden und für die es etablierten Source Code und Best Practices gibt. Eine Orientierungshilfe für entsprechende Fehlervermeidung bietet für Webanwendungen z. B. die OWASP Top 10 Liste. Dort werden jährlich die kritischen Schwachstellen für Webanwendungen dargestellt.
Ein weiterer Aspekt ist eine frühzeitige Planung und Einbeziehung von Sicherheitsaspekten in die Entwicklung. Dies vermeidet, dass notwendige Sicherheitsmaßnahmen fehlen und später teuer nachimplementiert werden müssen und die Ressourcen für das Projekt genauer bestimmt werden können.
Risiken bezogen auf unsichere Software können eine Reihe von Interessengruppen (Stakeholder) betreffen. Das offensichtlichste Problem, neben den bereits genannten finanziellen Schäden, können Softwareausfälle oder -einschränkungen in Folge von Sicherheitslücken sein.
Doch nicht immer sind Lücken im Programmcode eigenes Verschulden. Insbesondere durch die Einbindung von Bibliotheken oder Fremdsoftware können Sicherheitslücken im System auftreten. Als eines der bekanntesten Beispiele der letzten Jahre für ein entsprechendes Szenario kann der Java-Framework Log4j angeführt werden, an den viele Administratoren und Entwicklerteams leidvoll zurückdenken.
Die Entwendung von sensiblen Daten, sowohl interne als auch durch Kunden bereitgestellte, bedeutet einen massiven Reputationsverlust. Der Verstoß gegen Gesetze oder verbindliche Standards ist ein weiteres Risiko bei der Verwendung unsicherer Software. Daher lohnt sich nachfolgend der Blick auf den ISO/IEC-Standard und die darin gestellten Forderungen an sichere Programmierung.
Bisherige Umsetzung der Norm
Für die Auditierung und Zertifizierung eines Informationssicherheits-Managementsystems (ISMS) nach der ISO/IEC 27001 standen bisher als unterstützende Beschreibungen zum Thema „sichere Programmierung“ einige Maßnahmen aus dem Annex und der vorherigen Version der 27002 zur Verfügung. Innerhalb dieser Normen werden schon einige Aspekte angerissen, die nachfolgend wesentlich umfangreicher thematisiert werden. Ein zentraler Aspekt nach alter Norm betrifft die Dokumentation. Es soll im Stile von Arbeitsanweisungen den Entwicklern und weiteren berechtigten Interessierten am Quellcode nahegelegt werden, wie mit verschiedenen Programmiersprachen, der Verwaltung von Änderungen und weiteren Aspekten der Softwareentwicklung umgegangen werden soll.
Als eine Maßnahme für die sichere Programmierung gilt nach diesen alten Normen ein Systemsicherheitstest, bei dem nach vorher definierten Kriterien die fertige (Fremd-)Software und neue Versionen dieser geprüft werden sollen. Dazu zählt der Soll-Ist-Abgleich der Software mithilfe von Testeingaben unter verschiedenen Bedingungen und somit die testgetriebene Programmierung. Die Prüfung der Software sollte von unabhängigen Personen durchgeführt werden. Eine entsprechende Unabhängigkeit könnte durch spezialisierte externe Ressourcen oder durch interne Tester erzielt werden, die nicht direkt am Code mitgewirkt haben.
In der Vorgängerversion der 27002 ist eine kurze Liste an Anforderungen für sichere Programmierung gegeben. Einzug fanden bereits bei der Vorgängerversion eine sichere Entwicklungsumgebung und Sicherheitsanforderungen im Rahmen des Softwareengineerings. Zudem wurden sichere Repositorien und die Sicherheit bei der Versionskontrolle bezogen auf Anwendungssicherheit vorausgesetzt. Diese Aspekte der Anwendungssicherheit erfordern maßgeblich auch die Schulung und Qualifikation der beteiligten Entwickler, um etwaige Schwachstellen aufzufinden und idealerweise vorab bereits zu vermeiden.
Was ist neu?
Das Control 8.28 beschäftigt sich jetzt mit den Grundsätzen sicherer Programmierung (secure coding). Allgemein sollten demnach Firmen ein Mindestmaß an Sicherheit und Steuerung der eingesetzten Programmierungen gewährleisten. Als verwendete Programmierung sind dabei sowohl Eigenentwicklungen als auch Komponenten und Libraries aus eingebundener (Fremd-)Software zu verstehen. So weit, so gleich.
Im Gegensatz zu den bisherigen Anforderungen, gibt es in der neuen Norm eine Aufteilung der Softwareentwicklung in drei Phasen. Die Phase der Planung und Vorbereitung der Programmierung (Pkt. „Planning and before coding“), während der Programmierung (Pkt. „During coding“) und Nachbereitung in Form von Überprüfung und Wartung (Pkt. „Review and maintenance“).
Planung und Vorbereitung
Innerhalb der Fachabteilungen – bevor die erste Zeile Code geschrieben wurde – sollte sich auf übergreifende, gemeinsame Werte und anerkannte Prinzipien, wie die oberhalb beschriebenen OWASP Top 10 geeinigt werden. Diese gemeinsam erarbeiteten Grundsätze können in Folgeprojekten als Grundlage dienen, sollten jedoch in regelmäßigen Abständen überprüft werden. Ein Teil dieser Phase ist es auch, gängige Programmierungspraktiken zu hinterfragen, sofern diese zu Schwachstellen in bestehender oder neuer Software führen könnten. Grundlegend sollten ebenfalls die Programme, die für die Programmierung benötigt werden, bereits in dieser Phase bereitgestellt werden. Dazu zählen mindestens eine Entwicklungsumgebung, ein Repository, ein Buildserver und, je nach Bedarf und Größe des Teams, ein Tool zur Projektverwaltung und Organisation. Sofern es bereits eine Infrastruktur zur Entwicklung gibt, sollte diese regelmäßig gewartet und aktualisiert werden. Die Prüfung der Entwickler im Hinblick auf ihre Qualifikation ist ein weiterer Bestandteil, der bereits in der Vergangenheit Einzug in die Norm gefunden hat. Zudem sind zusätzliche Aspekte, wie die sichere Softwarearchitektur und Modellierung von Code, zu berücksichtigen. Die Trennung und Abgrenzung der Entwicklungsnetzwerke und -umgebungen von anderen Abteilungen, z. B. über VLANs, sollte ebenso erfolgen, um eine potentielle Gefährdung von anderen Netzwerksegmenten durch Schwachstellen und privilegierte Entwicklerclients zu vermeiden.
Die Programmierungsphase
Für die Entwicklung sollten während der Programmierung (in der Norm Pkt. „During coding“), weitere Aspekte beachtet werden, dazu zählt, sichere Praxen der jeweiligen Programmiertechniken anzuwenden und sich stets über Neuerungen der Programmiersprachen auf dem Laufenden zu halten.
Es hat sich bewährt, einige Techniken und Ideen der agilen Programmierung zu verwenden und gemeinhin zu akzeptieren. Hierzu zählt sicherlich das „pair programming“, bei dem an komplexen Zusammenhängen mit zwei Entwicklern agiert wird. Zusätzlich sollte geschriebener Code immer einen Review-Prozess durchlaufen und somit durch weitere Personen geprüft werden. Ein regelmäßiger Updatezyklus sollte unterbrochen werden, sofern es sicherheitsrelevante Schwachstellen in der Software gibt. Neben dem Review-Prozess sollte der Code und dazugehörige Funktionalitäten mithilfe von vorab definierten Tests qualitätsgesichert werden, bevor er produktiv verwendet wird. Eine entsprechende testgetriebene Codeerstellung sollte auch auf bei der Weiterentwicklung von bereits produktiv verwendetem Code eingesetzt werden, um frühzeitig Schwachstellen zu identifizieren, die durch neue Features in die Software gelangt sein können.
Der geschriebene Quellcode sollte nach gängiger Praxis dokumentiert sein und es sollte in regelmäßigen Abständen geprüft werden, ob er mithilfe eines Refactorings vereinfacht und optimiert werden kann. Ebenso sollten Programmstellen, die eine Schwachstelle enthalten könnten, ausgetauscht werden.
Ein besonderes Augenmerk wird auf den Ausschluss von Techniken gelegt, die per Design unsicher sind. Dazu zählt u. a. die Nutzung von hart codierten Passwörtern und nicht authentifizierten Webdiensten. Nicht genehmigte Code-Beispiele gilt es ebenfalls zu vermeiden. Damit ist gemeint, dass entsprechende Beispiele aus dem Internet vor der Nutzung im eigenen Quellcode gründlich geprüft werden. Eine entsprechende Prüfung sollte zudem die Lizenzkompatibilität betrachten und die Code-Beispiele sollten zur Lösung des Problems beitragen und keine zusätzlichen Sicherheitslücken in die Software hinzufügen.
Codewartung und -überprüfung
Entgegen der häufigen Wahrnehmung, endet die Arbeit an Software nicht mit der Fertigstellung des Quellcodes; innerhalb der Norm als Pkt. „Review and maintenance“ erfasst. Hier gilt es ebenfalls einige Punkte zu beachten. Neue Versionen sollten sicher bereitgestellt und ausgerollt werden. Sofern Sicherheitswarnungen oder Angriffsszenarien von Dritten gemeldet werden, sollten diese Meldungen zentral erfasst, nachverfolgt und behoben werden.
Mithilfe einer Protokollierungsfunktion sollte dokumentiert werden, ob potentielle Angriffe vorliegen und ob Fehler innerhalb der Software häufig auftreten. Entsprechende Fehler deuten häufig auf eine schlechte Anwendbarkeit hin oder können zu Schwachstellen führen und sollten behoben werden. Sofern Schwachstellen ausgenutzt wurden, gilt es zusätzliche Maßnahmen mit Unterstützung des Informationssicherheitsbeauftragten einzuleiten.
Der Quellcode sollte entsprechend der Schutzziele vor unberechtigtem Zugriff und Manipulation geschützt werden. Dafür können Konfigurationsmanagementtools dienen, da sie eine Reihe an Funktionen bereitstellen. Als Beispiele sind eine Versionierung und eine Zugriffskontrolle anzuführen.
Alternativ zur Verwendung von selbst geschriebener Software ist es legitim, Anwendungen oder Bibliotheken von Dritten einzubinden. Hierbei gilt es sicherzustellen, dass entsprechende Bibliotheken aktiv betreut und optimiert werden. Überdies sollte die Software insbesondere bei Aspekten wie der Authentifizierung und kryptographischen Verfahren gut geprüfte Bibliotheken verwenden.
Es gilt bei entsprechender Software die Lizenzen und weitere Aspekte wie die Historie und Sicherheit der Komponenten zu berücksichtigen und sicherherzustellen, dass die Software dauerhaft wartbar und einer vertrauenswürdigen Quelle zuzuschreiben ist.
Sofern Änderungen an der Fremdsoftware durchzuführen sind, sollte beachtet werden, dass entsprechende Änderungen das Risiko erhöhen, eingebaute Schutzmechanismen und die Integrität der Software zu beeinflussen. Vorweg sollte auch geprüft werden, ob eine Anpassung im Rahmen der Lizenzbedingungen erlaubt ist. Sofern es die Möglichkeit gibt, sollten dem Hersteller der Fremdsoftware die Änderungen zur Verfügung gestellt werden, sodass diese zum Standard der Fremdsoftware werden. Sofern Komponenten an Fremdsoftware weiterentwickelt werden, sollte berücksichtigt werden, dass eine weitere Abhängigkeit geschaffen wird und die Wartung der eigenen Änderungen als zusätzliche Aufgabe im Rahmen von Updates der Fremdsoftware hinzukommt.
Fazit
Aus der neuen Norm ergeben sich viele Aspekte ausführlicher, die zuvor nur aggregiert betrachtet wurden. Das neue Control „8.28 Secure coding“ kann für Entwicklungsteams als eine hinreichende Basis verwendet werden, um der Entwicklung in den drei logischen Phasen Vorbereitung, Programmierung und Nachbereitung einen Leitfaden bereitzustellen.
Die neuen Anforderungen, die sich aus dieser Norm ergeben, erfordern eine Umorientierung und eine genauere Unterscheidung in Eigen- und Fremdsoftware. Hierbei ist eine gute Kombination aus differenzierter Behandlung von Szenarien und unterstützenden Definitionen gelungen.