Kort sagt: PHP har färdiga, granskade funktioner för de vanligaste säkerhetsuppgifterna: password_hash() för lösenord, random_bytes() och random_int() för token, htmlspecialchars() mot cross-site scripting, förberedda frågor med PDO mot SQL-injektion, hash_equals() för säkra jämförelser och tillägget Sodium för kryptografi. Den som använder de här byggstenarna konsekvent undviker de flesta applikationsluckor. Mot fel i själva PHP-tolken, som vid PHP2Shell, hjälper de inte; där hjälper bara uppdateringen.
Varför inbyggda säkerhetsfunktioner i PHP?
Att skriva säkerhetskod själv är felbenäget. En egen lösenordshash, en hemmabyggd token-generator eller ett hopsnickrat filter för HTML-utskrifter ser ofta rätt ut och är det ändå inte. De inbyggda funktionerna är dokumenterade, testade och underhålls med PHP-uppdateringar.
För beslutsfattare betyder det: Fråga inte er byrå eller ert utvecklingsteam om säkerhetsfunktioner har byggts själva, utan om språkets standardfunktioner används. Tabellen ger en överblick.
| Uppgift | Funktion | Tillgänglig sedan | Viktig anmärkning |
|---|---|---|---|
| Lagra lösenord | password_hash(), password_verify() |
PHP 5.5 | kolumn upp till 255 tecken; bcrypt kortar till 72 byte |
| Slumpmässiga token | random_bytes(), random_int() |
PHP 7.0 | aldrig rand() eller mt_rand() för hemligheter |
| Slumptal objektorienterat | Random\Randomizer |
PHP 8.2 | samma säkerhet, flexiblare gränssnitt |
| Maskera HTML-utskrift | htmlspecialchars() |
alltid funnits | standardflaggor sedan 8.1 maskerar även enkla citattecken |
| Jämförelse i konstant tid | hash_equals() |
PHP 5.6 | användarinmatning som andra argument |
| Modern kryptografi | Sodium (sodium_*) |
PHP 7.2 | i stället för egen kryptering |
| Hemligheter i stacktraces | #[\SensitiveParameter] |
PHP 8.2 | värdet syns inte i tracen |
| Kontrollera inmatning | filter_var() |
PHP 5.2 | kontrollerar format, ersätter inte maskering |
Lösenord och token
password_hash() skapar en saltad hash, password_verify() kontrollerar den. Med PASSWORD_DEFAULT använder PHP för närvarande bcrypt; sedan PHP 8.4 ligger standardkostnadsfaktorn enligt manualen på 12 i stället för 10. Eftersom standardalgoritmen kan ändras rekommenderar manualen en databaskolumn med 255 tecken. Vid bcrypt kapas lösenord efter 72 byte, vilket är bra att tänka på vid mycket långa lösenfraser.
<?php
// Registrering
$hash = password_hash($passwort, PASSWORD_DEFAULT);
// Inloggning, inklusive automatisk uppgradering av gamla hashar
if (password_verify($eingabe, $hash)) {
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$hash = password_hash($eingabe, PASSWORD_DEFAULT); // spara på nytt
}
}
// Token för en länk för att återställa lösenordet
$token = bin2hex(random_bytes(32));
För jämförelser av hemligheter, till exempel en signatur, ska hash_equals() användas. En vanlig jämförelse med === kan enligt manualen via körtiden avslöja från vilken position två värden skiljer sig. Utförligare: Lagra lösenord säkert i PHP och säkra slumptal och token.
Maskera utskrifter och fråga databasen säkert
Cross-site scripting uppstår när användarinmatning hamnar ofiltrerad i HTML. htmlspecialchars() omvandlar specialtecken till HTML-entiteter. Sedan PHP 8.1 är standardflaggorna ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401; tidigare omvandlades enkla citattecken inte. Den som måste stödja äldre versioner anger flaggorna uttryckligen.
SQL-injektion förhindras av förberedda frågor. Värdena överförs skilt från SQL-texten och kan inte ändra frågan:
<?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');
Detaljerna finns under Förhindra cross-site scripting i PHP och på sidan om SQL-injektion.
Att kontrollera inmatning är ett andra, separat steg. filter_var() fastställer om ett värde har ett giltigt format, till exempel en e-postadress eller ett heltal inom ett tillåtet intervall. Det ersätter dock inte maskering vid utskrift och inte någon förberedd fråga, eftersom även formellt giltiga värden kan innehålla specialtecken.
Hålla hemligheter borta från felmeddelanden
En underskattad dataläcka är stacktraces. Uppstår ett fel i en funktion loggar PHP anropskedjan inklusive argumenten. Står ett lösenord eller en API-nyckel där hamnar den i loggen. Sedan PHP 8.2 markerar attributet #[\SensitiveParameter] sådana parametrar; deras värde syns då i tracen bara som objektet SensitiveParameterValue.
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
// ... kontroll ...
throw new RuntimeException('Datenbank nicht erreichbar');
}
Enligt en anmärkning i manualen verkar attributet bara på den konkreta implementeringen, inte på en metod i ett gränssnitt. Sätt det därför där koden faktiskt körs.
Sessioner: säkra inställningar och nya standarder
Sessioner är ett vanligt angreppsmål. Tre inställningar är centrala: session.use_strict_mode=1 avvisar sessions-id:n som servern inte själv har skapat; session.cookie_httponly=1 förhindrar åtkomst till sessionscookien via JavaScript; session.cookie_samesite=Lax försvårar att den skickas med från andra webbplatser. Enligt en antagen RFC blir just de här tre värdena standard med PHP 8.6. Sätt dem själva fram till dess, och även därefter uttryckligen, så att konfigurationen inte beror på standardvärdet.
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
Mer om det under Säkra sessioner i PHP.
Vad inbyggda funktioner inte klarar
PHP-projektet är tydligt i sin säkerhetspolicy: PHP är ingen sandlåda. Kringgående av open_basedir eller disable_functions, skadlig indata till unserialize() och ogranskade argument till funktioner som mysqli_query() räknas inte som säkerhetsluckor i PHP. För driftansvariga betyder det: De här inställningarna är en användbar härdning men ingen säkerhetsgräns, och unserialize() har inget med externa data att göra.
Den andra punkten gäller PHP2Shell. CVE-2026-109618 och CVE-2026-109619 möjliggör enligt php.net kodkörning innan eller medan er applikation körs; för mod_php visades en exploit innan någon applikationskod alls körs. Ingen funktion i er kod kan fånga det. Säker programmering och aktuell PHP-version är två skilda skyldigheter, och båda måste uppfyllas.
Hur hjälper PHP SOS konkret?
I säkerhetsgranskningen för PHP-applikationer kontrollerar vi målinriktat:
- Hantering av lösenord och token: Används
password_hash()ochrandom_bytes(), eller finns det egna hemmabyggen? - Utskrifter och frågor: Var hamnar inmatning ofiltrerad i HTML, SQL eller skalkommandon?
- Sessionskonfiguration: Är strict mode, HttpOnly, SameSite och Secure satta och inte möjliga att skriva över?
- Körmiljö: Körs en PHP-version som stöds med rättelserna från den 21 oktober 2026?
Vanliga frågor
Hur lagrar man lösenord rätt i PHP?
Med password_hash() och PASSWORD_DEFAULT, kontroll sker med password_verify(). Databaskolumnen bör enligt manualen rymma upp till 255 tecken, eftersom standardalgoritmen kan ändras i framtiden.
Passar rand() för token?
Nej. För token, nycklar och länkar för lösenordsåterställning ska random_bytes() eller random_int() användas. De ger enligt manualen kryptografiskt säkra slumpvärden.
Sedan när ingår Sodium i PHP?
Tillägget Sodium för modern kryptografi är sedan PHP 7.2.0 en del av PHP. Äldre versioner kunde bara komplettera det via PECL.
Skyddar de här funktionerna mot PHP2Shell?
Nej. De skyddar mot fel i er applikation. PHP2Shell sitter i själva tolken och stängs bara av en PHP-uppdatering, följd av omstart av alla PHP-processer.
Ändras sessionsstandarderna i PHP 8.6?
Ja, enligt en antagen RFC slås session.use_strict_mode och session.cookie_httponly på som standard och session.cookie_samesite sätts till Lax. Befintliga konfigurationer bör ni ändå sätta uttryckligen själva.