Kort sagt: PHP har færdige, afprøvede funktioner med til de hyppigste sikkerhedsopgaver: password_hash() til adgangskoder, random_bytes() og random_int() til tokens, htmlspecialchars() mod cross-site scripting, forberedte forespørgsler med PDO mod SQL-injection, hash_equals() til sikre sammenligninger og Sodium-udvidelsen til kryptografi. Den, der bruger disse byggesten konsekvent, undgår de fleste applikationssårbarheder. Mod fejl i selve PHP-fortolkeren, som ved PHP2Shell, hjælper de ikke; dér hjælper kun opdateringen.
Hvorfor indbyggede PHP-sikkerhedsfunktioner?
At skrive sikkerhedskode selv er fejlbehæftet. En egen adgangskode-hash, en selvbygget token-generator eller et hjemmestrikket filter til HTML-output ser ofte rigtigt ud og er det alligevel ikke. De indbyggede funktioner er dokumenterede, testede og vedligeholdes med PHP-opdateringer.
For beslutningstagere betyder det: Spørg ikke jeres bureau eller udviklingsteam, om sikkerhedsfunktioner er bygget selv, men om sprogets standardfunktioner bruges. Tabellen giver et overblik.
| Opgave | Funktion | Tilgængelig siden | Vigtig henvisning |
|---|---|---|---|
| Gemme adgangskoder | password_hash(), password_verify() |
PHP 5.5 | Kolonne til 255 tegn; bcrypt afkorter til 72 bytes |
| Tilfældige tokens | random_bytes(), random_int() |
PHP 7.0 | aldrig rand() eller mt_rand() til hemmeligheder |
| Tilfældighed objektorienteret | Random\Randomizer |
PHP 8.2 | samme sikkerhed, mere fleksibel grænseflade |
| Maskere HTML-output | htmlspecialchars() |
altid | Standard-flags siden 8.1 maskerer også enkelte anførselstegn |
| Tidskonstant sammenligning | hash_equals() |
PHP 5.6 | brugerinddata som andet argument |
| Moderne kryptografi | Sodium (sodium_*) |
PHP 7.2 | i stedet for egen kryptering |
| Hemmeligheder i stacktraces | #[\SensitiveParameter] |
PHP 8.2 | værdien vises ikke i tracen |
| Kontrollere inddata | filter_var() |
PHP 5.2 | kontrollerer format, erstatter ikke maskering |
Adgangskoder og tokens
password_hash() frembringer en saltet hash, password_verify() kontrollerer den. Med PASSWORD_DEFAULT bruger PHP aktuelt bcrypt; siden PHP 8.4 ligger standard-omkostningsfaktoren ifølge manualen på 12 i stedet for 10. Fordi standardalgoritmen kan ændre sig, anbefaler manualen en databasekolonne med 255 tegn. Ved bcrypt afskæres adgangskoder efter 72 bytes, hvilket skal overvejes ved meget lange adgangsfraser.
<?php
// Registrering
$hash = password_hash($passwort, PASSWORD_DEFAULT);
// Login, inklusive automatisk opgradering af gamle hashes
if (password_verify($eingabe, $hash)) {
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$hash = password_hash($eingabe, PASSWORD_DEFAULT); // gem på ny
}
}
// Token til et link til nulstilling af adgangskoden
$token = bin2hex(random_bytes(32));
Ved sammenligning af hemmeligheder, f.eks. en signatur, bør hash_equals() bruges. En almindelig sammenligning med === kan ifølge manualen via køretiden røbe, fra hvilket sted to værdier adskiller sig. Mere udførligt: Gem adgangskoder sikkert i PHP og sikre tilfældige tal og tokens.
Maskér output og forespørg databasen sikkert
Cross-site scripting opstår, når brugerinddata havner ufiltreret i HTML. htmlspecialchars() omdanner specialtegn til HTML-entiteter. Siden PHP 8.1 er standard-flagene ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401; før blev enkelte anførselstegn ikke omdannet. Den, der skal understøtte ældre versioner, angiver flagene udtrykkeligt.
SQL-injection forhindrer forberedte forespørgsler. Værdierne overføres adskilt fra SQL-teksten og kan ikke ændre forespørgslen:
<?php
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE email = :email');
$stmt->execute(['email' => $email]);
$kunde = $stmt->fetch();
echo htmlspecialchars($kunde['name'] ?? '', ENT_QUOTES, 'UTF-8');
Detaljerne står under Forhindr cross-site scripting i PHP og på siden om SQL-injection.
At kontrollere inddata er et andet, adskilt trin. filter_var() fastslår, om en værdi har et gyldigt format, f.eks. en e-mailadresse eller et heltal i et tilladt interval. Det erstatter dog hverken maskering ved output eller en forberedt forespørgsel, for også formelt gyldige værdier kan indeholde specialtegn.
Hold hemmeligheder ude af fejlmeddelelser
Et undervurderet datalæk er stacktraces. Opstår der en fejl i en funktion, logger PHP kaldskæden inklusive argumenter. Står der en adgangskode eller en API-nøgle deri, havner den i loggen. Siden PHP 8.2 markerer attributten #[\SensitiveParameter] sådanne parametre; deres værdi vises så i tracen kun som objektet SensitiveParameterValue.
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
// ... kontrol ...
throw new RuntimeException('Datenbank nicht erreichbar');
}
Ifølge en henvisning i manualen virker attributten kun på den konkrete implementering, ikke på en metode i et interface. Sæt den derfor dér, hvor koden faktisk kører.
Sessioner: sikre indstillinger og nye standarder
Sessioner er et hyppigt angrebsmål. Tre indstillinger er centrale: session.use_strict_mode=1 afviser sessions-id'er, som serveren ikke selv har frembragt; session.cookie_httponly=1 forhindrer adgang til sessions-cookien via JavaScript; session.cookie_samesite=Lax besværliggør, at den følger med fra fremmede sider. Ifølge den vedtagne RFC bliver netop disse tre værdier standard med PHP 8.6. Sæt dem selv indtil da, og også derefter udtrykkeligt, så konfigurationen ikke afhænger af standarden.
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
Mere om det under Sikr sessioner i PHP.
Hvad indbyggede funktioner ikke kan
PHP-projektet er i sin sikkerhedspolitik tydeligt: PHP er ingen sandbox. Omgåelser af open_basedir eller disable_functions, ondsindede inddata til unserialize() og ukontrollerede argumenter til funktioner som mysqli_query() gælder ikke som sikkerhedssårbarheder i PHP. For driftsansvarlige betyder det: Disse indstillinger er nyttig hærdning, men ingen sikkerhedsgrænse, og unserialize() har intet at gøre med fremmede data.
Det andet punkt angår PHP2Shell. CVE-2026-109618 og CVE-2026-109619 muliggør ifølge php.net kodeudførelse, før eller mens jeres applikation kører; ved mod_php blev der vist en exploit, før der overhovedet udføres applikationskode. Ingen funktion i jeres kode kan fange det. Sikker programmering og aktuel PHP-version er to adskilte forpligtelser, og begge skal opfyldes.
Hvordan hjælper PHP SOS konkret?
I sikkerhedsauditten for PHP-applikationer kontrollerer vi målrettet:
- Håndtering af adgangskoder og tokens: Bruges
password_hash()ograndom_bytes(), eller findes der egenbyggede løsninger? - Output og forespørgsler: Hvor havner inddata ufiltreret i HTML, SQL eller shell-kommandoer?
- Sessionskonfiguration: Er strict mode, HttpOnly, SameSite og Secure sat og ikke til at overskrive?
- Kørselsmiljø: Kører en understøttet PHP-version med rettelserne af 21.10.2026?
Ofte stillede spørgsmål
Hvordan gemmer man adgangskoder rigtigt i PHP?
Med password_hash() og PASSWORD_DEFAULT, kontrolleres sker med password_verify(). Databasekolonnen bør ifølge manualen kunne rumme op til 255 tegn, fordi standardalgoritmen kan ændre sig fremover.
Er rand() egnet til tokens?
Nej. Til tokens, nøgler og adgangskodelinks bør random_bytes() eller random_int() bruges. De leverer ifølge manualen kryptografisk sikre tilfældige værdier.
Siden hvornår er Sodium med i PHP?
Sodium-udvidelsen til moderne kryptografi er siden PHP 7.2.0 en del af PHP. Ældre versioner kunne kun eftermontere den via PECL.
Beskytter disse funktioner mod PHP2Shell?
Nej. De beskytter mod fejl i jeres applikation. PHP2Shell sidder i selve fortolkeren og lukkes kun ved en PHP-opdatering, efterfulgt af genstart af alle PHP-processer.
Ændrer sessionsstandarderne sig i PHP 8.6?
Ja, ifølge den vedtagne RFC slås session.use_strict_mode og session.cookie_httponly som standard til, og session.cookie_samesite sættes til Lax. Eksisterende konfigurationer bør I alligevel selv sætte udtrykkeligt.