Entdecken Sie das TÜV-zertifizierte GoogleTest mit Agentic AI für C/C++-Tests!
Details ansehen »
Parasoft-Blog
Die Implementierung und Aufrechterhaltung des richtigen Codierungsstandards für Ihre Entwicklungsprojekte ist der Schlüssel zur Bereitstellung sicherer Softwarelösungen. In diesem Beitrag erläutert unser Experte, warum Sie sicherstellen sollten, dass Sie den richtigen Codierungsstandard einhalten und wie Sie dies tun können.
Zum Abschnitt springen
Software hat sich vom Desktop auf nahezu alles ausgeweitet, was wir berühren. Von intelligenten Thermostaten über Infusionspumpen bis hin zu Autos ist Software allgegenwärtig und wächst stetig. Die sogenannten „Dinge“ des Internets der Dinge (IoT) enthalten zunehmend mehr Logik. Damit steigt auch das Ausfallrisiko. Viele dieser Geräte werden in sicherheitskritischen Bereichen wie der Medizin und der Automobilindustrie eingesetzt, wo sie ein hohes Verletzungsrisiko bergen.
Die meisten Unternehmen, die Geräte bauen, betrachten die aktuelle Softwareentwicklung zu Recht als eine fast schon verrückte Truppe von Cowboys und Chaos. Doch es gibt Hoffnung. Software KANN und MUSS als Ingenieurspraxis behandelt werden. Kodierungsstandards, die fester Bestandteil guter Softwareentwicklungspraxis sind, führen uns vom „Build, Fail, Fix“-Zyklus zu einem „Design, Build, Deliver“-Zyklus mit hoher Qualität, Sicherheit und Schutz.
Wie sich herausstellt, bieten dieselben Standards auch Vorteile im Bereich der Cybersicherheit und erfüllen somit eine doppelte Funktion.
Die Auswirkungen von Software auf die reale Welt werden häufig nicht berücksichtigt. Eines meiner Hauptthemen, über das ich als Evangelist bei Parasoft ständig diskutiere, ist, dass Softwareentwicklung eigentlich Engineering sein sollte.
Wir nennen sie Softwareingenieure, doch der Titel eilt der Praxis voraus. Programmieren wird erst dann zu Ingenieursarbeit, wenn die Arbeit durch einen Standard – einen Programmierstandard – geregelt wird, der beim Schreiben des Codes angewendet und durch Prüfungen sichergestellt wird. Das senkt die Kosten und erhöht die Qualität.
Das Zeitalter softwaredefinierter Fahrzeuge, medizinischer und industrieller IoT-Geräte sowie ständig vernetzter Geräte ist angebrochen. Software schleicht sich in Produkte, Geräte und andere Orte ein, an die wir nie gedacht hätten. Wir müssen jetzt gründlich über die Software in diesen Produkten und die damit verbundenen Auswirkungen nachdenken.
Eines der interessanten Dinge, die ich zu erklären versuche, ist, dass das Erstellen guter Software sich vom Erstellen eines Autos unterscheidet. Wenn ich versuche, ein hochwertiges Auto zu bauen, muss ich mehr für Materialien und mehr Zeit für den Bau aufwenden. Es stellt sich heraus, dass Sie in Software nicht mehr für die Erstellung hochwertiger Software ausgeben. Sie geben mehr aus, um Software von schlechter Qualität zu erstellen.
Wir müssen verstehen, dass in der Software die meisten Fehler vom Programmierer stammen, der sie in das Produkt einfügt. Wenn wir bei der Entwicklung der Software keine Fehler mehr einführen können, können wir viel bessere Software zu einem niedrigeren Preis haben.
Dieses Zitat stammt aus einem Vortrag von Edsger W. Dijkstra aus dem Jahr 1972 mit dem Titel „ Der bescheidene Programmierer “. Es ist auch heute noch hochaktuell.
Es ist wichtig zu verstehen, wie sich Qualität auf die Softwareentwicklungskosten auswirkt. Die Forscherin Capers Jones untersucht diesen Zusammenhang seit Jahrzehnten und führt jährlich eine Studie zu Softwarekosten durch. Die Zahlen ändern sich von Jahr zu Jahr kaum. Die Daten zeigen, dass die typischen Softwarekosten – von der Anforderungsanalyse über die Programmierung bis hin zur Wartung – mit jeder Phase steigen. Die Art und Weise, wie Teams mit Qualität umgehen, entscheidet jedoch darüber, ob ihr Prozess gesund oder problematisch ist.
Softwarequalität 2011: Ein Überblick über den Stand der Technik in der Software – Capers Jones
Es macht Sinn, dass die Kosten relativ gering sind, wenn wir einen Fehler direkt beim Schreiben des Codes finden – zum Beispiel ein paar Minuten Zeit eines Entwicklers. Wenn es gelingt, 85 % der Fehler in der Entwicklungsphase zu beseitigen, hat das große Auswirkungen auf die Kosten. Betrachten Sie die mittlerweile berühmte Grafik von Capers Jones, die die durchschnittlichen Kosten für die Behebung von Fehlern in jeder Entwicklungsphase zeigt:
Quellen – Applied Software Measurement, Capers Jones, 1996, Building Security into The Software Life Cycle, Marco M. Morana, 2006
Die Behebung von Fehlern nach der Veröffentlichung kostet etwa 16,000 US-Dollar (möglicherweise viel mehr), basierend auf Untersuchungen zu realen Unternehmen, die echte Software entwickeln, und nicht auf einem theoretischen Modell. Wenn wir uns die späten Qualitäts- und Sicherheitsbemühungen wie Penetrationstests ansehen, stellen wir fest, dass die hier festgestellten Sicherheitsprobleme am teuren Ende des Zyklus liegen. Es ist wahrscheinlich 15-mal so teuer wie das Auffinden von Schwachstellen durch Tests im Vergleich zu frühen Sicherheitsüberprüfungen.
Ein veralteter und nachweislich falscher Ansatz besteht darin, die Qualität Ihrer Software durch Tests am Ende des Lebenszyklus, kurz vor der Veröffentlichung, zu verbessern. In der Fertigungswelt ist man sich bewusst, dass dies unmöglich ist, aber aus irgendeinem Grund glauben wir, Qualität und Sicherheit in die Software hineintesten zu können.
Die Gründe, warum ich sage, dass Softwareentwicklung fast nie Engineering ist, sind diese gemeinsamen Merkmale der aktuellen Softwareentwicklung:
Das Ziel von Software-Codierungsstandards besteht darin, bewährte Programmierpraktiken einzuführen, die zu sicherem, zuverlässigem, testbarem und wartbarem Code führen. In der Regel bedeutet dies, bekannte unsichere Codierungspraktiken oder Code zu vermeiden, der unvorhersehbares Verhalten verursachen kann. Dies wird in Programmiersprachen wie C und C++ von entscheidender Bedeutung, in denen das Potenzial hoch ist, unsicheren oder unsicheren Code zu schreiben.
Ich denke jedoch, dass sich die Branche mit diesen Programmierstandards verirrt hat. In den letzten zehn Jahren haben sich die Tools (z. B. statische Analysetools) von der Erkennung potenziell problematischer Codes, die unsicher sind oder eine bekannte Sprachschwäche aufweisen, zu einem Fokus auf die Suche nach Fehlern als eine Form des frühen Testens, auch als Linksverschiebung bezeichnet, verschoben.
Obwohl das Suchen nach Fehlern wichtig ist, ist das Erstellen von Sound-Software eine produktivere Aktivität. Was wir tun sollten, ist die Erstellung und Durchsetzung von Standards, um die Situation zu vermeiden, in der Fehler überhaupt erst auftreten - und noch weiter nach links zu verschieben.
Zur Untermauerung dieser These sei auf die Forschung des Software Engineering Institute (SEI) verwiesen, die – wenig überraschend – ergab, dass Sicherheit und Zuverlässigkeit eng miteinander verbunden sind und die Sicherheit von Software anhand der Anzahl und Art der gefundenen Qualitätsmängel vorhergesagt werden kann. Kritische Fehler sind zudem häufig Programmierfehler, die sich durch Inspektionen und Werkzeuge wie die statische Codeanalyse vermeiden lassen.
Dieser Beitrag geht nicht näher auf jeden dieser Codierungsstandards ein, es gibt jedoch eine beträchtliche Menge an Arbeit in den folgenden Industriestandards. Obwohl ihre Anwendung möglicherweise spezifisch für einen bestimmten Typ ist, werden diese Standards in vielen Branchen übernommen. Hier sind einige Beispiele etablierter Codierungsstandards für Sicherheit und Schutz.
Betrachten wir MISRA C , das, wie bereits erwähnt, nicht nur für Automobilanwendungen gedacht ist. Es handelt sich um einen seit 1998 verwendeten und klar definierten Standard, der regelmäßig, etwa alle zwei Jahre, aktualisiert wird. Mit der Weiterentwicklung der Programmiersprachen C und C++ werden auch die zugehörigen Standards angepasst. MISRA C ist ein sehr flexibler Standard, der verschiedene Schweregrade berücksichtigt und eine dokumentierte Strategie für den Umgang mit und die Dokumentation von Abweichungen bietet.
Da Technologien wie die statische Codeanalyse Verstöße gegen Programmierrichtlinien aufdecken können, berücksichtigen neuere Versionen von MISRA , welche Richtlinien detektierbar (mit hoher Präzision durch entsprechende Tools erkennbar) und welche nicht. Dies führt uns zum Thema der Einführung und Durchsetzung von Programmierrichtlinien sowie zur Bedeutung statischer Analysetools für diese Richtlinien.
Untersuchungen zeigen, dass eine unzureichende Fehlerbeseitigung die Hauptursache für qualitativ schlechte Software ist. Programmierer sind zu etwa 35 % effizient darin, Fehler in ihrer eigenen Software zu finden. Später im Entwicklungszyklus liegen die meisten Fehler, die wir nach all den Design-Reviews, Peer-Reviews, Unit-Tests und Funktionstests beseitigen können, bei etwa 75 %.
Eine statische Analyse kann bei ordnungsgemäßer Verwendung in einem vorbeugenden Modus die Fehlerbeseitigung auf etwa 85% erhöhen. Der Schwerpunkt der statischen Analyse für die meisten Unternehmen liegt heute jedoch auf der Erkennung und der schnellen Lösung.
Weitere Vorteile sind möglich, wenn statische Analysewerkzeuge verwendet werden, um bekannte schlechte Programmierpraktiken und Sprachfunktionen zu verhindern. Hier kommen Codierungsstandards als Richtlinien und Teilmengen der Programmiersprache ins Spiel, die verhindern, dass häufig auftretende Fehler wie Pufferüberläufe oder fehlende Initialisierung in den Code geschrieben werden.
Stellen Sie sich vor, während eines Tests wird ein komplexer Pufferüberlauffehler entdeckt, beispielsweise mithilfe eines dynamischen Anwendungssicherheitstools (DAST). Dies ist ein Glücksfall, da Ihr Test zufällig den Codeabschnitt ausgeführt hat, der den Fehler enthält. Nach der Erkennung und Behebung des Fehlers muss der Test wiederholt werden usw. Eine statische Analyse mittels Ablaufanalyse hätte diesen Fehler möglicherweise ebenfalls gefunden, dies hängt jedoch von der Komplexität der Anwendung ab.
Die Laufzeitfehlererkennung ist präzise, prüft aber nur die tatsächlich ausgeführten Codezeilen. Ihre Aussagekraft hängt also von der Testabdeckung ab. Überlegen Sie, ob ein Programmierstandard den Code, der diesen Fehler überhaupt erst verursacht hat, von vornherein verboten hätte.
Codierungsstandards wie MISRA C beschreiben beispielsweise nicht, wie nicht initialisierter Speicher erkannt wird, sondern leiten Programmierer vielmehr dazu an, Code zu schreiben, der gar nicht erst zu einem solchen Fehler führt. Ich glaube, das ist eher ein technischer Ansatz: Programmieren nach bekannten und anerkannten Standards. Nehmen wir zum Beispiel Tiefbau und Brückenbau.
Wir würden nicht so vorgehen, eine Brücke zu bauen und sie dann zu testen, indem wir immer größere Lkw darüberfahren, bis sie zusammenbricht, das Gewicht des letzten Lkw messen, der die Brücke noch tragen kann, und sie dann so neu bauen, dass sie diesem neuen Gewicht standhält. Diese Vorgehensweise wäre töricht, ähnelt aber unserer Herangehensweise an die Softwareentwicklung.
Sobald ein Team einen Codierungsstandard einführt und die statische Analyse ordnungsgemäß anwendet, hört der Standard auf, ein Netz zu sein, durch das man den Code zieht, und beginnt, den Code während des Schreibprozesses zu formen.
Einen Fehler frühzeitig zu finden ist gut. Noch besser ist es, ihn gar nicht erst zu schreiben. Genau das bedeutet „Shift-Left“, konsequent umgesetzt: Probleme nicht nur früher zu erkennen, sondern den Standard bereits in den Moment der Codeerstellung zu verlagern, sodass das Problem gar nicht erst entsteht.
Hier beantwortet sich auch die Frage des Codierungsagenten von selbst. Immer mehr Code wird generiert, anstatt manuell eingegeben zu werden. Die logische Konsequenz ist die Frage, ob die Standards noch gelten.
Sie wenden sich häufiger an.
Entscheidend ist nicht, wer oder was den Code schreibt. Entscheidend ist, ob der Code den Standard erfüllt.
Prüft man den Code zum Zeitpunkt der Erstellung, entspricht er dem Standard. Führt man eine spätere Stapelprüfung durch, erhält man eine Liste der zu korrigierenden Fehler.
Ein Entwickler, dessen standardkonformer Linter während der Eingabe aktiv ist, befindet sich auf der richtigen Seite dieser Linie. Ebenso ein Codierungsagent mit statischer Analyse innerhalb seiner Schleife, der Code verwirft und neu generiert, bevor ein Mensch die Ausgabe überhaupt sieht.
Das reduziert den Code, der die Prüfung erreicht. Die Prüfung selbst wird dadurch nicht entfernt. Setzt man den Standard vor den Generator, liefert der Code weiterhin Fehler. Weniger als bei einer einfachen Eingabeaufforderung, aber nicht null.
Man macht also beides. Man orientiert die Generierung am Standard und überprüft dann das Ergebnis. Vertrauen ist gut, Kontrolle ist besser. Bei der Überprüfung spielt es keine Rolle, ob die Zeile von einer Person oder einem Modell geschrieben wurde. Die statische Analyse liest Code, nicht Autoren.
Betrachten wir die Heartbleed- Schwachstelle. Es gibt zwar mittlerweile Erkennungsmechanismen für diese spezielle Schwachstelle, aber man könnte den Code so schreiben, dass Heartbleed gar nicht erst auftreten kann. Vorbeugung ist die bessere und sicherere Methode.
Eine solide Präventionsmethodik ist günstiger als die Behebung der Fehler, die sie vermeidet.
„Wer wirklich zuverlässige Software will, wird feststellen, dass er zunächst Wege finden muss, die meisten Fehler zu vermeiden.“
—Dijkstra
Programmierrichtlinien sind verbindliche, solide Ingenieursprinzipien – die Verkörperung von Wissen, Praxis und Erfahrung. Das Wissen ist in der Richtlinie verankert, nicht im Kopf eines einzelnen Autors. Das macht sie zu echter Ingenieurskunst und nicht bloß zu Programmierung. Die Arbeit unterliegt einer Richtlinie, die beim Schreiben des Codes angewendet und bei der Freigabe überprüft wird. So ist das Ergebnis von vornherein korrekt und nicht erst nachträglich durch Fehlersuche behebbar.
Das Ziel war nie, besser im Finden von Fehlern zu werden. Es geht darum, keine Fehler mehr zu schreiben.
Repariere nicht den Code. Schreibe besseren Code.
Unabhängig davon, ob der Code von einem Entwickler oder einem Generator stammt, bleiben der Standard und die Überprüfung gleich.
Gute Software ist günstiger als schlechte. Wenn Sie bisher keine statische Codeanalyse nutzen oder diese nur zur Früherkennung einsetzen, empfehlen wir Ihnen die statischen Analysetools von Parasoft für C und C++ , Java , C# und VB.NET . Diese bieten eine umfangreiche Bibliothek mit Prüffunktionen für alle gängigen Sicherheitsstandards.
Auswählen und Implementieren des richtigen sicheren Codierungsstandards
Weiterführende Inhalte
Blog
6 min gelesen
Blog
9 min gelesen
Video