Titelkarte für „Security Code Review Explained“, die ein Code-Diff-Panel mit einer Original- und einer geänderten Zeile zeigt und darunter drei beschriftete Stufen: PATTERNS (deterministisch), dann PASS, dann REASONING (Modell).
Guides & Insights

Security-Code-Review erklärt: Worauf ein Reviewer in einem Diff achtet – und warum

Autor

Rowan Sterling

Veröffentlicht am

Neueste Modelle · 20Alle Modelle ansehen →
Benchmarks: Artificial Analysis · täglich aktualisiert
Zurück zu allen Beiträgen

Eine Sicherheitscodeüberprüfung ist das bewusste Lesen von Quellcode mit dem spezifischen Ziel, Wege zu finden, auf denen er dazu gebracht werden kann, etwas zu tun, das sein Autor nicht beabsichtigt hat. Diese Definition klingt offensichtlich, bis man sie mit dem vergleicht, was die meisten Teams tatsächlich durchführen: eine funktionale Überprüfung mit einer Sicherheits-Checkliste in der Nähe. Das OWASP Secure Code Review Cheat Sheet zieht die Grenze präzise: Eine Sicherheitsüberprüfung unterscheidet sich von einer funktionalen Überprüfung dadurch, dass sie auf Eingabevalidierung, Authentifizierung, Autorisierung, kryptografische Implementierung und Angriffsvektoren abzielt statt auf Korrektheit. Ein Diff, der einwandfrei funktioniert, kann einem Angreifer dennoch einen Weg in das System eröffnen, und nur eine dieser beiden Überprüfungen sucht danach.

Was das Thema jetzt statt 2020 einen Artikel wert macht, ist, dass ein Sprachmodell einen Diff kompetent, günstig und kontinuierlich lesen kann – was die Ökonomie der Prüfung verändert, ohne auch nur eine einzige der geprüften Dimensionen zu verändern. Die Checkliste ist älter als die Modelle und hat sich nicht verändert. Verändert hat sich, wie oft man es sich leisten kann, sie durchzugehen.

Worauf ein Reviewer beim Lesen tatsächlich achtet

Das OWASP-Cheat-Sheet organisiert die Arbeit in sechs Bereiche, und das Nützliche an der Liste ist, dass jeder Bereich eine Frage und keine Kategorie ist. Kategorien verleiten zum Abhaken; Fragen bringen Befunde hervor.

Card 'What a reviewer is actually looking for' listing six dimensions - input and injection, authn and session, authorization, cryptography, business logic, configuration and secrets - each with the question it answers about a diff.

Eingabe und Injection. Die Frage ist nicht, ob der Code einen Sanitizer hat; sie ist, ob irgendetwas einen Interpreter erreicht — Shell, SQL, Template-Engine, Ausdrucksauswerter — und auf welcher Ebene diese Anforderung durchgesetzt werden soll. Ein Diff, der eine parametrisierte Abfrage hinzufügt, ist gut; ein Diff, der eine parametrisierte Abfrage in eine Funktion einfügt, deren andere Aufrufer Rohstrings übergeben, ist ein Diff, der das Problem nur verschoben hat.

Authentifizierung und Sitzung. Wer ist der Aufrufer, und wie hat der Code das festgestellt? Der wiederkehrende Fehler ist nicht eine defekte Passwortprüfung, sondern eine Sitzung, die eine Rechteänderung überlebt – die Erhöhung findet statt, das Token behält seine alten Claims, und eine Stunde später sind die Rechte immer noch da.

Autorisierung.Prüfungen auf Objektebene, jedes Mal, bei jeder Route. Besonders achten sollte man in einem Diff auf eine neue Route, die nicht den Guard erbt, den ihre Geschwisterrouten haben, denn Middleware wird pro Router registriert, und eine Route, die unter einem anderen Router hinzugefügt wird, wird schlicht nicht abgedeckt.

Kryptografie. Primitive, Modus, Schlüssellänge und wo der Schlüssel liegt. Zwei Fragen decken die meisten echten Befunde auf: Kann jeder, der diesen Codebestand lesen kann, auch den Schlüssel lesen, und ist dieser Vergleich einer, der kein Timing preisgeben darf.

Geschäftslogik. Ob die Sequenz umgeordnet, erneut abgespielt oder durch Werte, die der Client gewählt hat, gesteuert werden kann. Ein Preis, eine Menge, eine Rolle oder ein Zustandsübergang, der vom Client eintrifft und serverseitig nicht neu abgeleitet wird, ist ein Befund – unabhängig davon, wie er validiert wird.

Konfiguration und Secrets. Was der Diff ausliefert, das niemals in einem Repository hätte sein dürfen, und ob die Standardwerte dort sicher sind, wo der Code tatsächlich läuft. Ein Debug-Flag, das standardmäßig auf true steht, ist ein Befund über die Produktion, nicht über das Flag.

Baseline-Review versus Diff-Review

OWASP unterscheidet zwei Modi, und deren Vermischung ist eine häufige Quelle sowohl für verschwendeten Aufwand als auch für trügerische Sicherheit. Eine Baseline-Überprüfung untersucht die Codebasis umfassend und ist das richtige Werkzeug für eine neue Anwendung oder ein größeres Release, für die Einführung eines Legacy-Systems, zur Erfüllung einer Compliance-Anforderung oder für die Post-Incident-Analyse, nachdem bereits etwas schiefgegangen ist. Eine diff-basierte Überprüfung betrachtet nur das, was sich geändert hat, und ist das richtige Werkzeug für Pull Requests, Commits, die Fertigstellung von Features und kontinuierliche Validierung.

Die Unterscheidung ist wichtig, weil die beiden unterschiedliche Arbeit erzeugen. Eine Baseline-Überprüfung endet mit einem Backlog; eine Diff-Überprüfung endet mit einer Merge-Entscheidung. Die erste kontinuierlich durchzuführen, ist unerschwinglich, und die zweite auf einer Codebasis durchzuführen, die die erste nie hatte, führt dazu, dass Teams ein falsches Gefühl von Abdeckung entwickeln: Jede Änderung besteht die Überprüfung, und die bereits vorhandene SQL-Konkatenation bleibt unangetastet.

Screenshot of the OWASP Cheat Sheet Series index entry for Secure Code Review, showing the introduction describing manual examination of source code for vulnerabilities automated tools miss, the baseline-versus-diff review split with their use cases, and a table of contents covering methodology, patterns, techniques, checklists and tools.

Techniken und was jede einzelne davon erkennt

OWASP nennt vier Review-Techniken, die sich danach unterscheiden, welcher Evidenz der Prüfer folgt, und nicht danach, wie gründlich sie sind. Code-Musteranalyse folgt vertrauten Formen: dem gefährlichen Funktionsaufruf, der Deserialisierung nicht vertrauenswürdiger Eingaben, der fehlenden Längenprüfung. Sie ist schnell und genau das, was ein deterministisches Werkzeug gut kann. Datenflussanalyse folgt einem Wert von seiner Eingangsstelle bis zu seiner Verwendung – die einzige Möglichkeit festzustellen, ob der vor drei Funktionen angewendete Sanitizer hier noch greift. Bedrohungsbasierte Überprüfung beginnt bei den Fähigkeiten eines Angreifers und arbeitet sich vorwärts – so erkennt man die Lücke zwischen zwei einzeln korrekten Komponenten. Geschäftslogikprüfung liest den Workflow statt die Zeilen und fragt, welche Abfolge legitimer Operationen einen illegitimen Zustand erzeugt.

Nur das erste dieser vier lässt sich mit einem Scanner gut abdecken, und nur das erste und das zweite lassen sich mit einem ungeführten Modelldurchlauf gut abdecken. Das ist kein Argument gegen Modelle; es ist ein Argument dafür, dem Prüfer zu sagen, welche Technik man möchte, denn ein Prompt, der nach „Sicherheitsproblemen“ fragt, wird zuverlässig eine Musteranalyse erzeugen und dann aufhören.

Was KI verändert hat – und was nicht

Die Forschung zu KI-generiertem Code hat den Review-Engpass verschärft, statt ihn erst zu schaffen. Die {{1}}NYU-Studie{{/1}} zu {{2}}GitHub Copilot{{/2}}-Vorschlägen, die 2022 auf {{3}}IEEE S&P{{/3}} veröffentlicht wurde, ergab, dass rund 40 % der generierten Snippets in 18 CWE-Kategorien ein ausnutzbares Muster enthielten. Die {{4}}Stanford-Arbeit{{/4}} zum Entwicklerverhalten, die 2023 auf {{5}}ACM CCS{{/5}} veröffentlicht wurde, fand den folgenschwereren Effekt: Entwickler, die Assistenten nutzten, waren zuversichtlicher, dass ihr Code sicher sei, produzierten aber messbar weniger sicheren Code. Mehr Output plus mehr Selbstsicherheit ist ein Review-Problem.

Ein Sprachmodell als Reviewer ändert eine Variable in dieser Gleichung – den Durchsatz. Es kann jeden Pull Request lesen, zu Kosten pro Token statt pro Seat, und man kann ihm die sechs oben genannten Fragen explizit stellen. Es ändert die Fragen nicht und erwirbt nicht die beiden Eigenschaften, die eine Review vertrauenswürdig machen: Determinismus und die Fähigkeit, den Code auszuführen. Derselbe Diff kann bei zweimaliger Überprüfung unterschiedliche Befunde ergeben, Schweregrade verschieben sich zwischen Läufen, und der Reviewer kann nicht belegen, dass ein markierter Pfad erreichbar ist.

Screenshot of the OrcaCode Review product page on OrcaRouter headed 'Open engine. Open prompt. Open bill.', describing a pull-request reviewer whose rules and merge gate run on GitHub under an MIT licence and are billed per token, with an example finding about an idempotency key that still varies in time.

OrcaCode Review ist die produktisierte Form dieser Idee, und es lohnt sich, sie genau zu betrachten, weil die Designentscheidungen die Fehlermodi offenlegen. Eine Review, die den fehlerhaften Fall als konkreten, reproduzierbaren Kommentar isoliert – dieser Schlüssel variiert noch zeitabhängig, sodass eine erneut versuchte Belastung einen neuen Schlüssel erzeugt und zu einer Doppelbelastung führen kann, hier ist die einzeilige Änderung –, leistet die Arbeit, die ein Reviewer leistet. Eine Review, die „potenzielles Sicherheitsproblem“ ohne Reproduktion meldet, betreibt Musteranalyse mit schlechterer Präzision als der Musterabgleicher. Und eine Regel- und Gate-Engine, die unter einer offenen Lizenz veröffentlicht wird, erhebt eine implizite Behauptung, die es zu prüfen lohnt: dass auch das Urteilsvermögen des Reviewers überprüfbar sein sollte.

Die zweischichtige Anordnung, die funktioniert

Bei einem deterministischen Scanner und einem probabilistischen Reviewer besteht die Anordnung, die sich in der Praxis bewährt, darin, jedem die Arbeit zu geben, die er tatsächlich gut kann. Der Scanner läuft bei jedem Push: Sekunden, kein Modell, keine Varianz, und fängt Secrets, gefährliche API-Aufrufe, unsichere Deserialisierung und halluzinierte Importe ab. Der Reviewer läuft bei jedem Pull Request: Minuten, modellgestützt, und erkennt die Logik zwischen den Zeilen – ob die Autorisierungsprüfung vor dem Fetch läuft, ob der Idempotenzschlüssel an einen stabilen Wert gebunden ist, ob die neue Route den Guard geerbt hat.

Dann die Ebene, die Leute überspringen: das Gate. Ein Befund, der einen Merge nicht blockiert, ist eine Benachrichtigung, und Benachrichtigungen werden freitags gelesen. Das Gate muss eng sein und absolut – kritische Befunde blockieren, alles andere kommentiert – und die Ausnahme muss schriftlich festgehalten werden, denn der Wert eines Gates liegt nicht darin, dass es den ersten Befund stoppt, sondern darin, dass es jede Umgehung sichtbar macht.

Die Änderung überprüfen, nicht die Codebasis

Die praktische Disziplin für ein Diff-Review ist eine kurze Abfolge, und ihr Wert liegt darin, dass sie an einem Nachmittag vermittelt werden kann. Lies den Diff daraufhin, was er hinzufügt zur Angriffsfläche, statt daraufhin, was er verändert. Verfolge bei jedem neuen Einstiegspunkt die Eingabe einen Schritt über das Ende des Diffs hinaus – die Schwachstelle steckt meist in der Funktion, die er aufruft und die der Autor nicht gelesen hat. Prüfe bei jeder neuen Route die Guard-Registrierung. Prüfe bei jeder neuen Abhängigkeit, ob sie existiert und ob jemand anderes den Namen veröffentlicht hat. Frage bei jedem neuen Konfigurationswert, welchen Default er dort hat, wo er tatsächlich ausgerollt wird.

Nichts davon erfordert, die Sprache gut zu beherrschen, weshalb es sich auf Prüfer skalieren lässt, die keine Sicherheitsspezialisten sind. Es erfordert jedoch, dass der Prüfer den Diff statt der Datei sieht, weil die gesamte Methode davon abhängt, zu wissen, was neu ist.

Und die ehrliche Grenze: Eine Diff-Überprüfung kann den Fehler nicht finden, der schon vor dem Diff da war. Wenn die Anwendung noch nie eine Baseline-Überprüfung hatte, ist die wertvollste verfügbare Sicherheitsarbeit nicht ein besserer Reviewer — es ist ein bewusster Durchgang über die Codebasis in den Bereichen, die Geld, Identität und Dateizugriff betreffen, mit den sechs oben genannten Fragen. Danach schützt jede weitere Diff-Überprüfung etwas, das bereits einmal angesehen wurde. Davor schützt jede Diff-Überprüfung etwas Unbekanntes.