Eine Version dieses Artikels erschien in DZone. Er wurde hier aktualisiert und syndiziert.
Seit einer gefühlten Ewigkeit diskutieren wir über den "Shifting Left" im SDLC, d. h. die Berücksichtigung bewährter Sicherheitspraktiken bereits zu Beginn der Softwareentwicklung. DevSecOps war ein großer Sprung nach vorn, nicht zuletzt wegen der Betonung der gemeinsamen Verantwortung für die Sicherheit und der Fähigkeit eines sicherheitsbewussten Entwicklers, häufige Schwachstellen schon beim Schreiben des Codes zu umgehen.
Wir wissen auch schon seit Äonen, dass die Art der Schulung für sicheren Code, mit der die Entwickler angesprochen und weitergebildet werden, den Unterschied ausmacht. Lösungen mit geringem Aufwand, die ausschließlich durch die Einhaltung von Vorschriften motiviert sind, bilden nicht die klugen Köpfe der Zukunft im Bereich Sicherheit, und die meisten Experten für Sicherheitsbewusstsein haben das erkannt. Dynamisches, kontextbezogenes Lernen ist am besten, aber es ist wichtig, dass die Nuancen darin verstanden werden.
Wenn wir eine Chance gegen Bedrohungsakteure haben wollen - und sie haben immer einen Vorsprung vor einem Unternehmen -, brauchen Entwickler eine ganzheitliche Schulungsumgebung mit mehrschichtigem Lernen, das kontinuierlich Fähigkeiten auf der Grundlage von Best Practices vermittelt.
Defensive Sicherheitsmaßnahmen, die von den Entwicklern ergriffen werden, sind nicht automatisch ein Gewinn.
Unser Ethos dreht sich darum, dass der Entwickler im Mittelpunkt einer präventiven Sicherheitsstrategie steht, und zwar schon auf der Code-Ebene aufwärts. Das ist eine Selbstverständlichkeit, und sicherheitskompetente Entwickler sind der einfachste Weg, um häufige Sicherheitslücken zu vermeiden, die sich in schlechten Codierungsmustern zeigen (wie z. B. Log4Shell, als ein aktuelles, verheerendes Beispiel).
Die Abwehrtechniken, die wir einsetzen können, um Entwickler weiterzubilden, sind jedoch unterschiedlich, auch wenn sie zu Recht in ein und demselben Trainingsbereich angesiedelt sind.
Stellen Sie sich zum Beispiel vor, man würde Ihnen sagen, wie Sie einen Kuchen backen sollen, und Sie würden nur Anweisungen verwenden, die darauf basieren, was Sie nicht tun sollen. "Überbacken Sie ihn nicht" und "Vergessen Sie die Eier nicht" lassen Raum für Interpretationen und bergen ein enormes Potenzial für Fehler, die zu einem Endergebnis führen, das für Geschafft!. Was man nicht tun sollte, ist ein sehr begrenzter Teil des Gesprächs und bietet keine praktischen Ratschläge für ein wirklich defensives Verhalten. Man kann den Entwicklern sagen: "Konfigurieren Sie diese API nicht falsch", aber wenn man nicht weiß, was eine korrekte und sichere Konfiguration ist, bleibt viel Raum für Fehler.
Entwickler werden keinen positiven Einfluss auf die Reduzierung von Schwachstellen haben, wenn sie nicht verstehen, wie die Schwachstellen funktionieren, warum sie gefährlich sind, welche Muster sie verursachen und welche Design- oder Codierungsmuster sie in einem Kontext beheben, der in ihrer Welt sinnvoll ist. Ein gerüstartiger Ansatz ermöglicht Wissensschichten, die ein vollständiges Bild davon vermitteln, was es bedeutet, sicher zu programmieren, eine Codebasis zu verteidigen und als sicherheitsbewusster Entwickler aufzutreten. Und ja, ein Teil dieses mehrschichtigen Lernens sollte der Offensive und dem Verständnis der Denkweise eines Angreifers gewidmet sein; dies ist entscheidend, um die Fähigkeiten des Querdenkens zu verbessern, die bei der Modellierung von Bedrohungen und Verteidigungsstrategien von unschätzbarem Wert sind.
Die Verstärkung schlechter Codierungsmuster ist ein Fallstrick, den wir nicht ignorieren können.
Eine unglückliche Tatsache bei einigen Methoden des Entwicklerlernens ist, dass der "defensive" Teil - selbst wenn die Schulung mit offensiven Techniken strukturiert ist - schlechte Gewohnheiten verstärken kann, selbst wenn sie technisch die Codesicherheit validieren.
Die Produktion von qualitativ hochwertigem Code sollte die Grundlage für jede Softwareentwicklung sein, aber die Definition von "Qualität" scheint immer noch umstritten zu sein. Tatsache ist, dass unsicherer Code nicht als Qualitätscode angesehen werden kann, selbst wenn er ansonsten funktional und schön ist. Der Clou ist, dass sicherer Code auch nicht von Natur aus hochwertig ist. Mit anderen Worten: Schlechte Codierungsmuster können zwar ein Sicherheitsproblem beheben, dabei aber ein weiteres einführen oder die Software möglicherweise ganz zerstören.
Werfen wir einen Blick auf ein Beispiel für schlechten Code in Form einer Korrektur für eine fehlerhafte Authentifizierung sowie auf die sicherste Version für die beste Praxis:
mit System;
using System.Collections.Generic;
mit System.Linq;
using System.Threading.Tasks;
mit Microsoft.AspNetCore.Authorization;
mit Microsoft.AspNetCore.Http;
mit Microsoft.AspNetCore.Mvc;
namespace BadFixesAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AlertsController : ControllerBase
{
private DatabaseContext context = new DatabaseContext();
[HttpGet(Name = "GetAlerts")]
// Does not ensure that the user is authenticated
public IEnumerable<Alert> Get()
{
return context.GetAlerts();
}
[HttpGet(Name = "GetAlerts")]
// Ensures that the user is authenticated, but does not check any roles
[Authorize()]
public IEnumerable<Alert> GetBadFix()
{
return context.GetAlerts();
}
[HttpGet(Name = "GetAlerts")]
// Ensures that the user is authenticated, AND that they have the "Administrator" role
[Authorize(Roles = "Administrator")]
public IEnumerable<Alert> GetGoodFix()
{
return context.GetAlerts();
}
}
}
Im ersten Ausschnitt wird nicht überprüft, ob der Benutzer authentifiziert ist, was so unsicher ist, wie es nur geht. Der zweite Ausschnitt ist zwar besser, da er eine Authentifizierungsprüfung durchführt, versäumt es aber, zugewiesene Rollen zu untersuchen und zu prüfen, ob die Berechtigungen für die angeforderten Informationen ausreichend sind. Die dritte prüft sowohl die Authentifizierung des Benutzers als auch, ob ihm die Rolle "Administrator" zugewiesen wurde. In einer Zeit, in der die Zugriffskontrolle mit den geringsten Privilegien in den meisten Fällen die Norm sein sollte, ist es von entscheidender Bedeutung, dass Rollen eingerichtet und überprüft werden, um sicherzustellen, dass der Zugriff auf Informationen nur auf einer Need-to-know-Basis erfolgt.
Die höchste Priorität für Entwickler ist es, Funktionen zu entwickeln, und obwohl die Sicherheit nicht absichtlich auf die lange Bank geschoben wird, verfügen sie nicht unbedingt über die Fähigkeiten, schlechte Codierungsmuster zu vermeiden, die zu Sicherheitsfehlern führen, und der Maßstab für einen guten Ingenieur umfasst selten sichere Codierungsfähigkeiten. Wir fördern indirekt diese schlechten Angewohnheiten, wenn die Funktionen großartig genug sind, und genau diese Denkweise muss sich ändern. Das Problem ist, dass die Art und Weise, wie manche Lernwege die praktische Codebereinigung fördern, potenziell auch sicheren, aber qualitativ minderwertigen Code begünstigt. Durch die Anwendung eines binären "Ja, das ist sicher / Nein, das ist nicht sicher" assessment, anstatt genauer zu prüfen, ob es wirklich der beste Ansatz ist, um den Fehler zu beheben und die Integrität der Software zu erhalten, gibt es Teufel im Detail, die unbemerkt bleiben.
Ohne die Entwickler durch den gesamten Prozess zu führen, um einen vollständigen Überblick über sichere Kodierung zu erhalten, führt dieser Ansatz zu denselben Problemen, die er zu lösen versucht. Stellen Sie sich vor, wir alle bekämen unseren Führerschein nur aufgrund unserer Fähigkeit, ein Fahrzeug zu einem bestimmten Ziel zu fahren; eine bestandene Prüfung, auch wenn wir rote Ampeln überfahren haben, durch eine Hecke gefahren sind und einen Fußgänger, der die Straße überquerte, knapp verpasst haben, um dort anzukommen. Wir haben das Ziel erreicht, aber der Weg dorthin ist das Wichtigste.
Die Entwickler müssen in die Lage versetzt werden, sich mehr um die Erstellung sicherer Software zu kümmern.
Der moderne Entwickler muss sich um viele Dinge kümmern, und es ist keine Überraschung, dass er Sicherheitsschulungen als langweilig empfindet, vor allem, wenn sie nicht mit Blick auf seinen Arbeitstag durchgeführt werden und ihn von seinen Terminen und Prioritäten ablenken. Es ist auch völlig unfair, ihre KPIs so zu ändern, dass sie einen Schwerpunkt auf sichere Programmierung legen, wenn sie nicht über die Fähigkeiten verfügen, die sie durch regelmäßige, passgenaue Lernmöglichkeiten und zusätzliche Tools erworben haben. Die Bedeutung der sicheren Softwareentwicklung kann jedoch gar nicht hoch genug eingeschätzt werden, und es ist von entscheidender Bedeutung, die Entwickler auf diese Seite zu ziehen.
Als ehemaliger Entwickler wollen wir in der Regel gute Arbeit leisten, und es ist sehr motivierend, wenn wir in Bezug auf die Qualität unserer Arbeit als besser angesehen werden als andere. Es ist eine Selbstverständlichkeit, Entwickler dazu zu motivieren, ihre Sicherheitsfähigkeiten kontinuierlich zu verbessern, und sie sollten dafür belohnt werden, dass sie die Bedeutung der Sicherheit auf Code-Ebene erkannt haben. Security-Champion-Programme, Bug-Bounties und Hackathons können großartige Gelegenheiten sein, eine positive Sicherheitskultur aufzubauen, und diejenigen, die die Ärmel hochkrempeln und sich engagieren, sollten die Beute erhalten.