Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Statisk analyse: PHPStan og Psalm

PHPStan og Psalm finder fejl i PHP-koden, uden at den udføres. Psalm sporer desuden usikre dataflow. Sårbarheder i selve PHP-fortolkeren finder ingen af dem.

Status 5 min. læsetidPHP-viden

Kort sagt: Statisk analyse kontrollerer PHP-kode, uden at den udføres, og finder på den måde typefejl, udefinerede variabler, død kode og kald på muligvis tomme værdier. De to udbredte værktøjer er PHPStan (regelniveauer 0 til 10) og Psalm (fejlniveauer 1 til 8, desuden en taint-analyse for usikre dataflow). De finder fejl i jeres applikation, ikke i PHP-fortolkeren; mod sårbarheder som PHP2Shell hjælper kun PHP-opdateringen.

Hvad er statisk analyse?

En test udfører kode og sammenligner resultatet. Statisk analyse læser derimod koden som en meget grundig kontrollør og slutter sig ud fra typer, returværdier og kald til, hvor noget kan gå galt. Den finder fejl også i grene, som ingen test nogensinde når.

For beslutningstagere er nytten enkel: Fejl, der findes før lanceringen, koster en brøkdel af fejl, som kunderne opdager. For udviklere er den en stadig ledsager, der kører med i udviklingsmiljøet og i CI-pipelinen. Slår analysen an ved en ændring, overtages den ikke, før fejlen er rettet. Sådan vokser der ingen ny arvelast frem, mens den eksisterende afvikles trin for trin. Sammen med tests med PHPUnit og Pest udgør den fundamentet for kodekvaliteten.

PHPStan: regelniveauer fra 0 til 10

PHPStan installeres som udviklingsafhængighed og kræver for at køre PHP fra 7.4:

composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse src tests

Uden yderligere angivelse kontrollerer PHPStan kun det nødvendigste. Strengheden styrer I via elleve niveauer, hvert rummer de underliggende:

Niveau Hvad der desuden kontrolleres (udvalg)
0 ukendte klasser og funktioner, forkert antal argumenter, altid udefinerede variabler
3 returtyper og typer, der tildeles egenskaber
5 typer på argumenter ved funktions- og metodekald
6 manglende typeangivelser
8 metodekald og egenskabstilgange på værdier, der kan være null
10 strengeste omgang med mixed, også ved manglende typer

Med --level max kører altid det højeste niveau. Dokumentationen advarer dog om, at en opgradering af PHPStan så kan give mange nye meddelelser. Et typisk fund fra niveau 8:

<?php
function kundenname(?Kunde $kunde): string
{
    return $kunde->name();   // PHPStan: kald på en værdi, der kan være null
}

Indfør PHPStan uden en syndflod af fejl: baselinen

I gamle projekter melder PHPStan på højt niveau ofte hundredvis af steder. Baselinen løser problemet: Den gemmer alle eksisterende meddelelser i en fil, og PHPStan melder derefter kun nye fejl.

vendor/bin/phpstan analyse --level 6 src tests --generate-baseline

Den genererede fil phpstan-baseline.neon binder I ind i konfigurationen:

includes:
    - phpstan-baseline.neon

parameters:
    level: 6
    paths:
        - src
        - tests

Sådan forbliver den gamle beholdning synligt dokumenteret, mens ny kode skal være ren fra begyndelsen.

Psalm og taint-analysen

Psalm forfølger lignende mål som PHPStan. Niveauerne løber omvendt: 1 er det strengeste, 8 det mest eftergivende, standarden er 2. Psalm kræver PHP fra 8.2 og opsættes sådan:

composer require --dev vimeo/psalm
./vendor/bin/psalm --init
./vendor/bin/psalm --taint-analysis

Taint-analysen er særlig interessant for sikkerheden. »Taint« betyder forurening: Psalm markerer data fra kilder, som en angriber kan kontrollere, f.eks. $_GET, $_POST, $_COOKIE, $_REQUEST eller php://input. Derefter sporer den, om disse data uden beskyttelse når frem til farlige steder, de såkaldte sinks: output med echo, include, header eller SQL-forespørgsler. Til de indbyggede kategorier hører blandt andet sql, html, shell, include, eval, ssrf og unserialize.

<?php
// Psalm melder et flow fra $_GET til HTML-outputtet (kategori html)
echo 'Hallo ' . $_GET['name'];

// Rettet: maskér outputtet efter konteksten
echo 'Hallo ' . htmlspecialchars($_GET['name'] ?? '', ENT_QUOTES, 'UTF-8');

Psalm-dokumentationen nævner åbent grænserne: Analysen forudsætter, at maskeringen sker korrekt. Fine fejl, f.eks. manglende anførselstegn om en HTML-attribut, kan alligevel efterlade sårbarheder. Psalm anbefaler derfor parametriserede forespørgsler til SQL og kontekstbevidste skabeloner til HTML. Resultater kan udsendes i SARIF-formatet, som blandt andet GitHub Code Scanning forstår.

Statisk analyse og sikkerhed efter PHP2Shell

Her er en ærlig afgrænsning på sin plads. PHP2Shell, altså CVE-2026-109618 og CVE-2026-109619, sidder i PHP-fortolkeren. Intet værktøj, der læser jeres applikationskode, finder disse sårbarheder, og ingen kodeændring lukker dem. Det kan kun opdateringen til PHP 8.5.12, 8.4.27, 8.3.36 eller 8.2.35.

Alligevel bidrager statisk analyse til sikkerheden, på tre punkter:

  1. Opgraderingsevne: Den finder kode, der ikke længere kører på nye PHP-versioner. Dermed falder tærsklen for at skifte fra 8.1 eller 8.2 til en understøttet version.
  2. Egne sårbarheder: Taint-analysen finder veje til SQL-injection, cross-site scripting eller filinkludering. PHP-projektet gør i sin sikkerhedspolitik klart, at ukontrollerede inddata til funktioner som mysqli_query() ikke er en fejl i PHP, men ligger i applikationens ansvar.
  3. Robusthed: Mange fatale fejl opstår ved kald på null eller forkerte typer. php.net anbefaler i forbindelse med CVE-2026-109619 udtrykkeligt at rette fatale fejl i applikationen, som kan udløses udefra.

Statisk analyse erstatter ikke en sikkerheds-kodegennemgang foretaget af mennesker, men gør den mere effektiv, fordi rutinefejl er sorteret fra på forhånd.

Hvordan hjælper PHP SOS konkret?

Som led i sikkerhedsaudit og penetrationstest går vi frem på denne måde:

  • Opsætte værktøjer: PHPStan eller Psalm med passende niveau og baseline, integreret i jeres eksisterende pipeline.
  • Vurdere sikkerhedsfund: Vi gennemgår resultaterne af taint-analysen og skiller reelle risici fra falske alarmer.
  • Forberede opgradering: Vi viser, hvilke steder der blokerer for et skift til en understøttet PHP-version.
  • Overdrage resultater: I får en prioriteret liste med konkrete kodesteder til jeres team eller bureau.

Ofte stillede spørgsmål

Hvad er forskellen på PHPStan og Psalm?

Begge kontrollerer typer og finder fejl uden udførelse. PHPStan tæller sine niveauer fra 0 (løst) til 10 (strengt), Psalm fra 8 (løst) til 1 (strengt). Psalm har en indbygget taint-analyse for sikkerhedsproblemer.

Kan jeg indføre PHPStan i et gammelt projekt?

Ja. Med en baseline gemmer PHPStan alle eksisterende meddelelser i en fil og melder derefter kun nye fejl. Så starter teamet uden en syndflod af fejl og afvikler arvelasten trin for trin.

Finder statisk analyse PHP2Shell?

Nej. PHP2Shell sidder i PHP-fortolkeren, ikke i jeres kode. Mod det hjælper kun PHP-opdateringen. Statisk analyse hjælper dog med at forberede koden til nye PHP-versioner, så opdateringen bliver mulig hurtigere.

Hvilket niveau bør man vælge?

Til starten et lavt niveau uden baseline eller et højere niveau med baseline. Vigtigere end tallet er, at analysen kører automatisk ved hver ændring og ikke lader nye fejl slippe igennem.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp