GitLab SAST und Dependency Scanning in bestehende PHP- und Node-Pipelines integrieren
AI generated
CI/CD
.yml
GitLab · CI/CD · Security
GitLab SAST und Dependency Scanning in bestehende Pipelines integrieren
Konfiguration, Findings-Triage und False-Positive-Handling

Statische Codeanalyse und Abhaengigkeitspruefung gehoeren zu den Security-Funktionen, die GitLab direkt eingebaut mitliefert und die sich mit wenigen Zeilen in eine bestehende .gitlab-ci.yml einbinden lassen. Der eigentliche Aufwand beginnt aber erst danach: Ergebnisse muessen bewertet, echte Schwachstellen priorisiert und Falschmeldungen sauber unterdrueckt werden, ohne dass das Security-Rauschen die Entwicklerakzeptanz untergraebt. Dieser Artikel zeigt die Integration von SAST und Dependency Scanning in eine bestehende PHP- oder Node-Pipeline sowie den praktischen Umgang mit den gemeldeten Findings.

17 Min. Lesezeit SAST Dependency Scanning Security Vulnerability Management

1. Was SAST und Dependency Scanning jeweils leisten

Static Application Security Testing, kurz SAST, analysiert den eigenen Quellcode ohne ihn auszufuehren und sucht nach bekannten unsicheren Mustern wie unsanitisierten SQL-Queries, unsicherer Deserialisierung oder hartcodierten Zugangsdaten. Dependency Scanning dagegen betrachtet nicht den eigenen Code, sondern die Liste der eingebundenen Drittanbieter-Pakete, etwa aus composer.lock oder package-lock.json, und gleicht sie mit einer Datenbank bekannter Schwachstellen ab. Beide Analysen ergaenzen sich, weil ein Grossteil realer Sicherheitsluecken heute in Abhaengigkeiten steckt, nicht im selbst geschriebenen Code.

GitLab liefert fuer beide Analysearten fertige CI/CD-Templates mit, die als include:template eingebunden werden und automatisch die passenden Analyzer fuer die im Repository erkannten Sprachen auswaehlen. Fuer eine PHP-Codebasis kommt dabei zum Beispiel semgrep als SAST-Analyzer und gemnasium-php als Dependency-Scanner zum Einsatz, fuer Node.js entsprechend semgrep und gemnasium-nodejs. Diese automatische Erkennung nimmt viel manuelle Konfigurationsarbeit ab, funktioniert aber nur zuverlaessig, wenn die Projektstruktur den ueblichen Konventionen der jeweiligen Sprache folgt.

2. SAST in eine bestehende Pipeline einbinden

Die Grundintegration ist bewusst minimal gehalten: Ein include:template Eintrag fuer Security/SAST.gitlab-ci.yml reicht aus, um die passenden Analyzer-Jobs automatisch der Pipeline hinzuzufuegen. GitLab fuehrt intern eine Erkennung der im Repository vorhandenen Sprachen durch und aktiviert nur die tatsaechlich relevanten Analyzer, sodass in einem reinen PHP-Projekt kein unnoetiger Java- oder Go-Scan mitlaeuft. Die Ergebnisse werden am Ende als SAST-Report-Artifact abgelegt, das GitLab automatisch im Merge-Request-Widget als Security-Findings-Liste anzeigt.

Fuer bestehende, bereits gewachsene Pipelines ist wichtig, dass der SAST-Job standardmaessig in der Stage test laeuft. Ist diese Stage in der eigenen .gitlab-ci.yml nicht vorhanden oder anders benannt, muss entweder die eigene Stage-Liste um test ergaenzt oder der SAST-Job explizit einer vorhandenen Stage zugewiesen werden. Ein haeufiger Stolperstein ist zudem, dass SAST bei sehr grossen Monorepos deutlich laenger laeuft als der Rest der Pipeline, weshalb sich eine eigene, parallele Stage fuer Security-Jobs oft lohnt, um die Gesamtlaufzeit nicht unnoetig zu verlaengern.


# .gitlab-ci.yml
stages:
  - build
  - test
  - security
  - deploy

include:
  - template: 'Security/SAST.gitlab-ci.yml'

semgrep-sast:
  stage: security

3. Dependency Scanning fuer PHP und Node einbinden

Dependency Scanning wird analog ueber include:template mit Security/Dependency-Scanning.gitlab-ci.yml eingebunden und erkennt Manifestdateien wie composer.lock, package-lock.json oder yarn.lock automatisch. Fuer PHP-Projekte muss composer install vor dem Scan-Job gelaufen sein, damit die vollstaendige Abhaengigkeitsstruktur inklusive transitiver Pakete verfuegbar ist, andernfalls analysiert der Scanner nur eine unvollstaendige Teilmenge. Bei Node-Projekten gilt entsprechend, dass npm ci oder yarn install vorher ausgefuehrt sein sollte, damit die Lockfile-Version mit der tatsaechlich installierten Version uebereinstimmt.

Ein wichtiger praktischer Unterschied zu SAST ist, dass Dependency Scanning auf eine regelmaessig aktualisierte, extern gepflegte Vulnerability-Datenbank angewiesen ist. Neue Schwachstellen in bereits eingebundenen Paketen koennen daher auch dann auftauchen, wenn sich am eigenen Code seit Wochen nichts geaendert hat, einfach weil eine neue CVE fuer eine bestehende Abhaengigkeit veroeffentlicht wurde. Genau das macht die Kombination mit einer Scheduled Pipeline sinnvoll, die regelmaessig unabhaengig von Code-Aenderungen nach neuen Findings sucht.


# .gitlab-ci.yml
include:
  - template: 'Security/Dependency-Scanning.gitlab-ci.yml'

gemnasium-php-dependency_scanning:
  stage: security
  before_script:
    - composer install --no-dev --prefer-dist

4. Wie GitLab Findings darstellt und priorisiert

Jedes gemeldete Finding erhaelt automatisch eine Schweregradeinstufung von Info ueber Low, Medium und High bis Critical, basierend auf dem CVSS-Score der zugrunde liegenden Schwachstelle oder der Regelklassifikation des SAST-Analyzers. Im Merge-Request-Widget erscheinen neue Findings direkt bei der betroffenen Codezeile beziehungsweise beim betroffenen Paket, sodass Reviewer sie sehen, ohne einen separaten Report oeffnen zu muessen. Das Security-Dashboard auf Projekt- und Gruppenebene aggregiert zusaetzlich alle Findings ueber die Zeit und macht Trends sichtbar, etwa ob die Zahl offener High-Severity-Findings steigt oder faellt.

Fuer die Priorisierung im Alltag hat sich bewaehrt, sich zunaechst ausschliesslich auf Critical- und High-Findings zu konzentrieren und Medium- sowie Low-Findings in regelmaessigen, aber weniger haeufigen Reviews zu behandeln, etwa monatlich statt bei jedem Merge Request. Ohne diese Priorisierung droht ein Team schnell in einer Flut von Findings unterzugehen, von denen viele geringe reale Auswirkung haben, waehrend die tatsaechlich kritischen Funde in der Masse untergehen.

5. Vom Finding zum behobenen Issue: Ein praktischer Workflow

Ein bewaehrter Workflow beginnt damit, jedes Critical- oder High-Finding direkt aus dem Security-Dashboard heraus in ein GitLab-Issue umzuwandeln, was GitLab mit einem einzigen Klick erlaubt und automatisch alle relevanten Metadaten wie betroffene Datei, Zeilennummer und CVE-Referenz mitgibt. Dieses Issue durchlaeuft dann denselben Priorisierungs- und Zuweisungsprozess wie jeder andere Bug, statt in einer separaten, oft vernachlaessigten Security-Liste zu verschwinden.

Bei Dependency-Scanning-Findings ist die Loesung haeufig ein simples Versions-Update der betroffenen Abhaengigkeit, was sich mit composer update paketname oder npm update paketname umsetzen laesst, gefolgt von einem erneuten Pipeline-Lauf zur Bestaetigung. Bei SAST-Findings im eigenen Code ist dagegen meist eine echte Code-Aenderung noetig, etwa der Wechsel von einer unsicheren String-Konkatenation in einer SQL-Query zu einem parametrisierten Statement, was in der Regel einen eigenen Merge Request mit Review verdient statt eines schnellen Patches ohne Zweitpruefung.

6. Umgang mit False Positives

Kein automatisierter Scanner ist perfekt, und sowohl SAST als auch Dependency Scanning erzeugen gelegentlich Findings, die bei genauerer Pruefung keine echte Schwachstelle darstellen. Ein klassisches Beispiel ist ein SAST-Finding fuer eine vermeintlich unsichere Funktion, die im konkreten Kontext bereits durch eine vorgelagerte Validierung abgesichert ist, oder ein Dependency-Finding fuer ein Paket, dessen verwundbarer Codepfad im eigenen Projekt gar nicht genutzt wird. Solche Faelle direkt als erledigt zu ignorieren, ohne sie zu dokumentieren, fuehrt dazu, dass derselbe Scanner beim naechsten Lauf erneut denselben Alarm ausloest.

GitLab bietet dafuer im Security-Dashboard die Moeglichkeit, ein Finding explizit als False Positive zu markieren, inklusive eines Pflichtfeldes fuer die Begruendung. Diese Markierung wird dauerhaft gespeichert und verhindert, dass dasselbe Finding bei zukuenftigen Scans erneut als offen auftaucht, solange sich der zugrunde liegende Code oder die Abhaengigkeitsversion nicht aendert. Wichtig ist, diese Begruendungen tatsaechlich sorgfaeltig zu dokumentieren, da eine spaetere Ueberpruefung durch einen Security-Auditor sonst nicht nachvollziehen kann, warum ein Finding als unkritisch eingestuft wurde.


# .gitlab-ci.yml: Ausschluss eines Pfads von SAST
variables:
  SAST_EXCLUDED_PATHS: "spec, test, tests, tmp, vendor/legacy-lib"

7. Schwellenwerte und Pipeline-Verhalten bei Findings steuern

Standardmaessig blockiert ein Security-Finding die Pipeline nicht automatisch, sondern erscheint lediglich als Information im Merge-Request-Widget, damit Entwickler nicht durch jeden einzelnen Low-Finding an einem Merge gehindert werden. Fuer strengere Anforderungen laesst sich ueber Security-Policies auf Gruppen- oder Projektebene ein sogenanntes Scan Result Policy definieren, das zum Beispiel jeden Merge mit einem ungeloesten Critical-Finding automatisch blockiert, bis entweder eine Behebung erfolgt oder eine autorisierte Ausnahme genehmigt wurde.

Diese Policies lassen sich granular konfigurieren, etwa nur fuer bestimmte Branches wie main greifen zu lassen, waehrend Feature-Branches weiterhin frei entwickelt werden koennen. In regulierten Umgebungen, in denen Compliance-Vorgaben eine dokumentierte Freigabe fuer jede bekannte Schwachstelle verlangen, ist eine solche Policy oft unverzichtbar, waehrend kleinere Teams haeufig mit der reinen Sichtbarkeit im Merge-Request-Widget gut zurechtkommen, ohne harte Blockaden einzufuehren.

8. Auswirkungen auf Pipeline-Laufzeit und Ressourcenverbrauch

SAST- und Dependency-Scanning-Jobs benoetigen eigene, teils recht speicherintensive Analyzer-Container, was die Gesamtlaufzeit einer Pipeline spuerbar verlaengern kann, insbesondere bei grossen Codebasen. In der Praxis hat es sich bewaehrt, diese Jobs in einer eigenen, parallel zu Test-Jobs laufenden Stage zu platzieren, statt sie sequentiell nach den funktionalen Tests einzureihen, sodass sich Test- und Security-Laufzeit ueberlappen statt zu addieren.

Fuer sehr grosse Repositories bietet sich zudem an, Dependency Scanning nicht bei jedem Push, sondern nur bei Merge Requests gegen den main-Branch sowie zusaetzlich per Scheduled Pipeline nachts laufen zu lassen, wie im vorangegangenen Artikel zu Scheduled Pipelines beschrieben. Das reduziert den CI-Minuten-Verbrauch spuerbar, ohne die Sicherheit zu gefaehrden, da neue Schwachstellen in bestehenden Abhaengigkeiten ohnehin unabhaengig vom Zeitpunkt eines Commits erkannt werden muessen.

9. Best Practices fuer den nachhaltigen Betrieb

Ein nachhaltiger Security-Scanning-Betrieb braucht klare Verantwortlichkeiten: Wer sichtet neue Findings, wer entscheidet ueber False-Positive-Markierungen und wer eskaliert Critical-Findings ausserhalb des normalen Sprint-Rhythmus. Ohne diese Klarheit verwaisen Findings im Dashboard und die anfaengliche Investition in die Integration verpufft, weil niemand die gemeldeten Probleme tatsaechlich abarbeitet.

Ebenso wichtig ist ein regelmaessiger Blick auf die False-Positive-Rate: Steigt sie ueber die Zeit deutlich an, deutet das oft auf eine zu aggressive Analyzer-Konfiguration hin, die durch gezieltes Anpassen der SAST_EXCLUDED_PATHS oder durch Deaktivieren einzelner, projektspezifisch irrelevanter Regeln reduziert werden kann. Die folgende Tabelle vergleicht die wichtigsten Eigenschaften von SAST und Dependency Scanning, um beide Analysearten klar voneinander abzugrenzen.

Merkmal SAST Dependency Scanning
Analysiert Eigenen Quellcode Eingebundene Drittanbieter-Pakete
Datenquelle Statische Analyzer-Regeln Externe Vulnerability-Datenbank
Aendert sich ohne Code-Aenderung Nein Ja, bei neuer CVE fuer bestehendes Paket
Typische Behebung Code-Aenderung mit Review Versions-Update der Abhaengigkeit
Empfohlener Rhythmus Bei jedem Merge Request Merge Request plus naechtliche Scheduled Pipeline

Mironsoft

CI/CD-Pipelines, Zero-Downtime-Deployments und Release-Automatisierung

Deployments, die ohne Ausfallzeit und ohne Nervenkitzel laufen?

Wir prüfen bestehende GitLab-Pipelines auf fragile Deployment-Schritte und fehlende Absicherung und bauen daraus einen Release-Prozess mit Zero-Downtime-Deployments, automatisierten Checks und einem Rollback, dem ihr im Ernstfall vertrauen könnt.

Pipeline-Review

Bestehende .gitlab-ci.yml auf Fragilität, fehlende Stages und Sicherheitslücken prüfen.

Zero-Downtime-Deployment

Symlink-Releases, Health-Checks und Rollback-Strategien für Magento-Shops aufbauen.

CI/CD-Automatisierung

Tests, Security-Scans und Deployments zu einer zuverlässigen Pipeline verbinden.

10. Zusammenfassung

GitLab SAST und Dependency Scanning: Das Wichtigste auf einen Blick

Zwei Analysearten

SAST prueft eigenen Code, Dependency Scanning prueft Drittanbieter-Pakete gegen eine Vulnerability-Datenbank.

Minimale Integration

Ein include:template Eintrag reicht aus, GitLab erkennt Sprachen und passende Analyzer automatisch.

Findings triagieren

Critical und High priorisiert in Issues umwandeln, Medium und Low in regelmaessigen Reviews behandeln.

False Positives dokumentieren

Explizite Markierung im Security-Dashboard mit Begruendung statt stillem Ignorieren.

11. FAQ: GitLab SAST und Dependency Scanning: Das Wichtigste auf einen Blick

1Wie binde ich SAST in eine bestehende Pipeline ein?
Ueber einen include:template Eintrag fuer Security/SAST.gitlab-ci.yml in der .gitlab-ci.yml. GitLab erkennt automatisch die im Repository vorhandenen Sprachen und aktiviert die passenden Analyzer, ohne dass weitere Konfiguration noetig ist.
2Muss composer install vor dem Dependency-Scanning-Job laufen?
Ja, fuer PHP-Projekte muss composer install vorher ausgefuehrt sein, damit die vollstaendige Abhaengigkeitsstruktur inklusive transitiver Pakete fuer den Scanner verfuegbar ist. Andernfalls wird nur ein unvollstaendiger Teil der Abhaengigkeiten geprueft.
3Wo sehe ich neue Security-Findings?
Direkt im Merge-Request-Widget bei der betroffenen Codezeile oder dem betroffenen Paket sowie aggregiert im Security-Dashboard auf Projekt- oder Gruppenebene, das auch Trends ueber die Zeit anzeigt.
4Wie markiere ich ein Finding als False Positive?
Im Security-Dashboard laesst sich jedes Finding explizit als False Positive markieren, inklusive eines Pflichtfeldes fuer die Begruendung. Die Markierung bleibt bestehen, solange sich der betroffene Code oder die Paketversion nicht aendert.
5Blockiert ein gefundenes Critical-Finding automatisch den Merge?
Standardmaessig nicht. Dafuer muss explizit eine Scan Result Policy auf Gruppen- oder Projektebene eingerichtet werden, die Merges mit ungeloesten Critical-Findings gezielt blockiert, bis eine Behebung oder genehmigte Ausnahme vorliegt.
6Warum tauchen neue Findings auf, obwohl sich der Code nicht geaendert hat?
Dependency Scanning greift auf eine extern gepflegte, regelmaessig aktualisierte Vulnerability-Datenbank zu. Wird eine neue CVE fuer ein bereits eingebundenes Paket veroeffentlicht, erscheint das Finding beim naechsten Scan, auch ohne eigene Code-Aenderung.
7Wie schliesse ich bestimmte Verzeichnisse von SAST aus?
Ueber die Variable SAST_EXCLUDED_PATHS, die eine kommagetrennte Liste von Pfaden entgegennimmt, zum Beispiel Test-Verzeichnisse oder Legacy-Code, der bewusst nicht gescannt werden soll.
8Verlangsamt SAST die Pipeline spuerbar?
Bei groesseren Codebasen ja. Es empfiehlt sich, SAST- und Dependency-Scanning-Jobs in einer eigenen, parallel zu funktionalen Tests laufenden Stage zu platzieren, um die Gesamtlaufzeit nicht sequentiell zu verlaengern.
9Sollte Dependency Scanning bei jedem Push laufen?
Fuer sehr grosse Repositories bietet sich an, es nur bei Merge Requests gegen main sowie zusaetzlich nachts per Scheduled Pipeline laufen zu lassen, um CI-Minuten zu sparen, ohne neue Schwachstellen zu uebersehen.
10Wie gehe ich mit der Vielzahl an Low- und Medium-Findings um, ohne das Team zu ueberlasten?
Bewaehrt hat sich, sich im Tagesgeschaeft auf Critical- und High-Findings zu konzentrieren und Medium- sowie Low-Findings in einem separaten, weniger haeufigen Review-Rhythmus, etwa monatlich, gesammelt zu bearbeiten.