Die Symfony Code-Audit-Checkliste: worauf ein erfahrener Reviewer achtet

Eine Checkliste für das Audit einer Symfony-Codebasis: Abhängigkeiten, Sicherheit, Doctrine-Performance, Test-Realität und Deployment-Risiko.

Isometrische 3D-Illustration eines siebenstufigen Symfony-Audits als mehrstöckiges Gebäude dargestellt, wobei jede Ebene Themen wie Dependency-Hygiene, statische Analyse, Sicherheit, Datenbank-Performance, Tests, Deployment und Observability visualisiert, umgeben von Entwicklerwerkzeugen und Architektur-Büchern.

Die meisten Symfony-Audits, für die ich beauftragt werde, kommen in derselben Form an. Jemand in der Leitung hat ein schlechtes Gefühl. Ein Senior-Engineer hat gerade gekündigt. Ein Vendor-Pitch liegt auf dem Tisch. Der Aufsichtsrat stellt spitze Fragen zum technischen Risiko. Die Codebasis hat seit Jahren keine frischen Augen gesehen, und niemand intern kann selbstbewusst beantworten: “Ist das Ding in Form oder nicht?”

Dieser Essay ist die Checkliste, die ich abarbeite, wenn diese Frage auf meinem Tisch landet. Sie ist nicht vollständig. Es sind die sieben Ebenen, die in meiner Erfahrung über 90 Prozent des Risikos einer typischen Symfony-Codebasis abdecken. Jede dauert zwischen 30 Minuten und einigen Stunden. Das Ganze, ernsthaft gemacht, ist eine Woche. Als Smoke-Test ist es ein Nachmittag. Beide Varianten lohnen sich vor jeder größeren Investitionsentscheidung.

Ebene 1: Dependency- und Versions-Hygiene

Öffnen Sie composer.json und composer.lock. Achten Sie auf drei Dinge.

PHP-Version. Alles unter 8.2 ist seit Ende 2025 ohne Security-Support (siehe PHP supported versions). Apps auf 8.0 oder 7.x sind kein “Legacy”, sondern ein Compliance-Thema. Die Kosten eines PHP-Upgrades sind endlich. Die Kosten einer ungepatchten Runtime auf einem zahlungsverarbeitenden System nicht.

Symfony-Version. Alles unter 6.4 LTS ist außerhalb des Community-Supports. 7.x ist die aktuelle Major-Spur. Eine Codebasis, die zwei Majors hintereinander übersprungen hat, ist meist schmerzhaft, aber nicht katastrophal; eine, die noch auf 4.x oder 5.x ist, ist ein Projekt, kein Audit-Finding.

Verlassene Pakete. composer audit und composer outdated --direct decken das meiste auf. Alles im Dependency-Baum, das nicht gepflegt wird, eine bekannte CVE hat oder im projekteigenen Vendor-Verzeichnis geforkt ist, ist einen Absatz im Report wert. Zusatz: prüfen Sie, ob irgendwo dev-master oder Git-Refs gepinnt sind. Meist nicht. Wenn doch, erklärt es viel.

Ebene 2: Statische Analyse

Lassen Sie vendor/bin/phpstan analyse --level=max gegen src/ laufen. Die Ausgabe ist das aussagekräftigste Artefakt eines Audits. Drei Muster, auf die Sie achten:

  • Fehler pro Datei, sortiert. Die obersten fünf Dateien sind die, aus denen der nächste Bug kommt. Immer. Notieren Sie sie.
  • Unterdrückte Regeln. Suchen Sie nach phpstan-ignore-line und @phpstan-ignore über das Repo verteilt. Häufung zählt mehr als die reine Anzahl. Zwanzig Suppressions in einem riskanten Service sind ein schlechteres Signal als 200 gleichmäßig über eine große Codebasis verteilte.
  • Größe der Baseline-Datei. Eine lange Baseline ist ein aufgeschobenes Problem. Eine Codebasis mit 3000 Fehlern in der Baseline auditieren heißt, eine Codebasis zu auditieren, in der das Team aufgehört hat, PHPStan durchzusetzen.

Wenn PHPStan überhaupt nicht konfiguriert ist, ist das das Headline-Finding. Überspringen Sie zum nächsten.

Ebene 3: Sicherheitsoberfläche

Ich brauche keinen vollen Pentest, um einen brauchbaren Sicherheitsabsatz zu schreiben. Ich muss fünf Dinge bestätigen.

  1. Symfony Security wird genutzt, keine handgeschriebene Session. Greppen Sie nach UserPasswordHasher und der Firewall-Konfiguration. Handgerollte Auth ist fast immer falsch.
  2. CSRF ist für zustandsändernde Formulare aktiv. Prüfen Sie framework.csrf_protection: true und die Nutzung von _token in Templates.
  3. Content-Security-Policy-Header ist gesetzt, mit Nonce, nicht unsafe-inline. Inspizieren Sie die Response im Browser. Lesen Sie den relevanten Header.
  4. Input wird über Symfony Validator an der Grenze validiert. Ein Controller, der rohes $request->get('email') in die Domain-Schicht zieht, ist ein Geruch.
  5. Doctrine-Queries sind parameterisiert. Greppen Sie nach ->getQuery() neben String-Konkatenation. Selten, aber wenn es auftaucht, ist es ein kritisches Finding.

Ein sauberer Fünf-Punkte-Sicherheitsabsatz ist nützlicher als ein 40-seitiger Tool-Report, weil die Leitung, die das Audit liest, danach handeln kann. Siehe auch: Das ehrliche Architektur-Review für die Gewichtung von Findings im Endbericht.

Ebene 4: Doctrine und die Datenbank

Hier verdient ein Symfony-Audit sein Honorar. Datenbankprobleme verstecken sich besser als Code-Probleme und sie töten mehr Apps.

Holen Sie das Slow-Query-Log der letzten 14 Tage. Holen Sie den EXPLAIN-Plan der Top-10-Queries. Suchen Sie nach:

  • Sequentiellen Scans auf Tabellen mit über 100k Zeilen. Fast immer ein fehlender Index.
  • Wiederholten identischen Queries in einem einzelnen Request. N+1. Häufig nach Entity-Änderungen, die die Fetch-Joins nicht nachzogen.
  • Migrations mit down()-Methoden, die werfen. Gut, das ist hier Konvention. Migrations mit down()-Methoden, die nicht werfen, sind ein Hinweis darauf, dass jemand migrate:down in Produktion ausgeführt hat. Finden Sie heraus, wer.
  • Schema- und Code-Drift. Lassen Sie doctrine:schema:validate laufen. Die Ausgabe sollte leer sein. Wenn nicht, beschreibt das Produktions-Schema nicht mehr das, was die Entities beschreiben, und Sie sind ein Deploy von einer Überraschung entfernt.

Der Post Doctrine-Performance-Muster, die wirklich wichtig sind deckt ab, was mit den Findings zu tun ist.

Ebene 5: Test-Realität vs. behauptete Coverage

Lassen Sie die Test-Suite laufen. Notieren Sie Anzahl der Tests, Laufzeit und Fehlerrate bei einem Cold-Checkout. Dann achten Sie auf die Lücke zwischen Coverage als Zahl und Coverage als Eigenschaft.

Ein Repo kann 70 Prozent Coverage berichten und null nützliche Tests haben, wenn alle Unit-Tests die Datenbank, die Queue und die HTTP-Schicht mocken. Die Zahl zählt weniger als die Antwort auf: “Wenn ich den wichtigsten User-Flow breche, fängt das ein Test?” Finden Sie den Test, der Signup, Login oder Checkout abdeckt, und prüfen Sie, was er tatsächlich asserted. Bestätigt der Test nur, dass keine Exception flog, ist die Coverage Theater.

Achten Sie auch auf das Flaky-Suite-Signal: einen .phpunit-rerun-Marker, Retries in der CI-Konfiguration oder Commit-Messages mit “fix flaky test”. Jeder Punkt ist ein Debt-Eintrag. Jeder Retry ist ein Bug, den das Team gemutet hat.

Ebene 6: Deployment und Rollback

Lesen Sie das Deploy-Skript. Meist in bin/, tools/ oder einem Makefile. Drei Fragen:

  1. Wie groß ist das Downtime-Fenster? “Null” ist erreichbar, aber nur, wenn der Migration-Schritt ein Expand-Contract-Muster nutzt (siehe Zero-Downtime Doctrine Migrations). Ein Deploy, der doctrine:migrations:migrate synchron gegen die Produktions-DB ausführt, während die App Traffic serviert, ist ein Deploy, der irgendwann eine Tabelle so lange sperrt, dass jemand geweckt wird.
  2. Wie sieht der Rollback-Pfad aus? “Commit revertieren und neu deployen” ist okay für Code. Es ist nicht okay, wenn die Migration destruktiv war. Jeder Deploy, dessen Vorwärtsschritt nicht ohne Backup-Restore reversibel ist, gehört in die Findings.
  3. Sind Feature-Flags oder Canary-Deploys im Einsatz? Wenn jede Änderung beim ersten Deploy 100 Prozent des Traffics erreicht, ist das Team einen schlechten PR von einem Vorfall entfernt, der sonst ein Paging auf einer kleinen Scheibe gewesen wäre.

Ebene 7: Observability

Die letzte Ebene ist die billigste, die hinzuzufügen ist, und die, die am häufigsten fehlt. Ich schaue nach:

  • Strukturierten Logs mit Request-IDs, die sich über Services propagieren.
  • APM (Tideways, New Relic, Datadog, was auch immer) mit mindestens Transaction-Tracing auf den Top-Endpunkten.
  • Error-Tracking (Sentry oder äquivalent) mit unbehandelten Exceptions verdrahtet.
  • Eine Postmortem-Kultur, wie leichtgewichtig auch immer. Siehe Das Postmortem-Format, das Vorfälle reduziert.

Eine Codebasis ohne Observability ist eine Codebasis, in der das Team von Vorfällen durch den Kunden erfährt.

Die 60-Minuten-Variante

Wenn Sie nur eine Stunde haben:

  1. composer outdated --direct und composer audit.
  2. phpstan analyse --level=max src und die obersten 50 Zeilen lesen.
  3. doctrine:schema:validate.
  4. Test-Suite laufen lassen und die Zeit messen.
  5. Das Deploy-Skript öffnen und Stück für Stück lesen.

Diese Stunde liefert 80 Prozent dessen, was ein volles Audit sagen würde. Die verbleibenden 20 Prozent sind das, was ein echtes Engagement rechtfertigt.

Wenn Sie vor einer großen Entscheidung ein erfahrenes Augenpaar auf Ihrer Codebasis brauchen, starten unsere Engagements zu Technischen Schulden und unser Architektur-Review mit dieser Checkliste. Der vollständige Report endet mit einem priorisierten Backlog, das Sie tatsächlich finanzieren können.

Referenzen

Bereit, Ihre Architektur in den Griff zu bekommen?

Buchen Sie ein kostenloses 30-minütiges Gespräch mit Silas. Kein Verkaufsgespräch, nur ein direkter Austausch über Ihre Herausforderungen.

Antwort in der Regel innerhalb von 24 Stunden.

Kostenloses Gespräch buchen