Ukratko: PHP za najčešće sigurnosne zadaće donosi gotove, provjerene funkcije: password_hash() za lozinke, random_bytes() i random_int() za tokene, htmlspecialchars() protiv cross-site scriptinga, pripremljene upite s PDO-om protiv SQL injectiona, hash_equals() za sigurne usporedbe i ekstenziju Sodium za kriptografiju. Tko te gradivne elemente dosljedno koristi, izbjegava većinu ranjivosti u aplikacijama. Protiv pogrešaka u samom PHP interpreteru, kao kod PHP2Shella, ne pomažu; ondje pomaže samo ažuriranje.
Zašto ugrađene PHP sigurnosne funkcije?
Pisati sigurnosni kod vlastitim snagama sklono je pogreškama. Vlastiti hash lozinke, samostalno izrađen generator tokena ili improvizirani filtar za HTML izlaze često izgledaju ispravno, a nisu. Ugrađene funkcije su dokumentirane, testirane i održavaju se PHP ažuriranjima.
Za donositelje odluka to znači: ne pitajte svoju agenciju ili razvojni tim jesu li sigurnosne funkcije izrađene samostalno, nego koriste li se standardne funkcije jezika. Tablica daje pregled.
| Zadaća | Funkcija | Dostupno od | Važna napomena |
|---|---|---|---|
| Spremanje lozinki | password_hash(), password_verify() |
PHP 5.5 | stupac do 255 znakova; bcrypt skraćuje na 72 bajta |
| Slučajni tokeni | random_bytes(), random_int() |
PHP 7.0 | nikad rand() ili mt_rand() za tajne |
| Slučajnost objektno orijentirano | Random\Randomizer |
PHP 8.2 | ista sigurnost, fleksibilnije sučelje |
| Maskiranje HTML izlaza | htmlspecialchars() |
oduvijek | zadane zastavice od 8.1 maskiraju i jednostruke navodnike |
| Usporedba u konstantnom vremenu | hash_equals() |
PHP 5.6 | korisnički unos kao drugi argument |
| Moderna kriptografija | Sodium (sodium_*) |
PHP 7.2 | umjesto vlastitog šifriranja |
| Tajne u stack traceovima | #[\SensitiveParameter] |
PHP 8.2 | vrijednost se ne pojavljuje u traceu |
| Provjera unosa | filter_var() |
PHP 5.2 | provjerava format, ne zamjenjuje maskiranje |
Lozinke i tokeni
password_hash() stvara hash sa solju, a password_verify() ga provjerava. S PASSWORD_DEFAULT PHP trenutačno koristi bcrypt; od PHP-a 8.4 zadani faktor troška prema priručniku iznosi 12 umjesto 10. Budući da se zadani algoritam može promijeniti, priručnik preporučuje stupac u bazi podataka od 255 znakova. Kod bcrypta se lozinke odrezuju nakon 72 bajta, što treba imati na umu kod vrlo dugih lozinki-rečenica.
<?php
// Registracija
$hash = password_hash($passwort, PASSWORD_DEFAULT);
// Prijava, uključujući automatsko unaprjeđivanje starih hasheva
if (password_verify($eingabe, $hash)) {
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$hash = password_hash($eingabe, PASSWORD_DEFAULT); // spremiti iznova
}
}
// Token za poveznicu za resetiranje lozinke
$token = bin2hex(random_bytes(32));
Za usporedbe tajni, primjerice potpisa, treba koristiti hash_equals(). Obična usporedba s === prema priručniku može vremenom izvršavanja odati od kojeg se mjesta dvije vrijednosti razlikuju. Opširnije: Sigurno spremanje lozinki u PHP-u i sigurni slučajni brojevi i tokeni.
Maskiranje izlaza i siguran upit u bazu podataka
Cross-site scripting nastaje kad korisnički unosi nefiltrirani završe u HTML-u. htmlspecialchars() pretvara posebne znakove u HTML entitete. Od PHP-a 8.1 zadane su zastavice ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401; prije toga jednostruki navodnici nisu se pretvarali. Tko mora podržavati starije verzije, zastavice navodi izričito.
SQL injection sprječavaju pripremljeni upiti. Vrijednosti se prenose odvojeno od SQL teksta i ne mogu promijeniti upit:
<?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');
Pojedinosti su na stranici Sprječavanje cross-site scriptinga u PHP-u i na stranici o SQL injectionu.
Provjera unosa drugi je, zaseban korak. filter_var() utvrđuje ima li vrijednost valjan format, primjerice e-adresa ili cijeli broj u dopuštenom rasponu. To, međutim, ne zamjenjuje maskiranje pri ispisu ni pripremljeni upit, jer i formalno valjane vrijednosti mogu sadržavati posebne znakove.
Tajne držati podalje od poruka o pogreškama
Podcijenjeno curenje podataka su stack traceovi. Kad se u funkciji dogodi pogreška, PHP zapisuje lanac poziva zajedno s argumentima. Ako se u njemu nalazi lozinka ili API ključ, završava u zapisniku. Od PHP-a 8.2 atribut #[\SensitiveParameter] označava takve parametre; njihova se vrijednost u traceu tada pojavljuje samo kao objekt SensitiveParameterValue.
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
// ... provjera ...
throw new RuntimeException('Datenbank nicht erreichbar');
}
Prema napomeni u priručniku atribut djeluje samo na konkretnoj implementaciji, a ne na metodi sučelja. Postavite ga stoga ondje gdje se kod stvarno izvršava.
Sesije: sigurne postavke i novi standardi
Sesije su čest cilj napada. Tri su postavke ključne: session.use_strict_mode=1 odbija ID-ove sesija koje poslužitelj nije sâm stvorio; session.cookie_httponly=1 sprječava pristup kolačiću sesije putem JavaScripta; session.cookie_samesite=Lax otežava slanje uz sadržaj sa stranih stranica. Prema prihvaćenom RFC-u upravo te tri vrijednosti postaju zadane s PHP-om 8.6. Do tada ih postavite sami, a i poslije toga izričito, kako konfiguracija ne bi ovisila o zadanoj vrijednosti.
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
Više u članku Osiguravanje sesija u PHP-u.
Što ugrađene funkcije ne mogu
PHP projekt u svojim je sigurnosnim smjernicama jasan: PHP nije sandbox. Zaobilaženja open_basedir ili disable_functions, zlonamjerni unosi u unserialize() i neprovjereni argumenti u funkcijama poput mysqli_query() ne smatraju se sigurnosnim ranjivostima PHP-a. Za operatere to znači: te su postavke korisno ojačavanje, ali nisu sigurnosna granica, a unserialize() s tuđim podacima nema što tražiti.
Druga točka tiče se PHP2Shella. CVE-2026-109618 i CVE-2026-109619 prema php.net omogućuju izvršavanje koda prije ili tijekom rada Vaše aplikacije; kod mod_php-a pokazan je exploit prije nego što se uopće izvrši kod aplikacije. Nijedna funkcija u Vašem kodu to ne može presresti. Sigurno programiranje i aktualna verzija PHP-a dvije su odvojene obveze i obje moraju biti ispunjene.
Kako PHP SOS konkretno pomaže?
U sigurnosnom auditu za PHP aplikacije ciljano provjeravamo:
- Postupanje s lozinkama i tokenima: Koriste li se
password_hash()irandom_bytes()ili postoje vlastita rješenja? - Izlazi i upiti: Gdje unosi nefiltrirani završavaju u HTML-u, SQL-u ili shell naredbama?
- Konfiguracija sesija: Jesu li postavljeni Strict Mode, HttpOnly, SameSite i Secure, i ne mogu li se prepisati?
- Vrijeme izvođenja: Radi li podržana verzija PHP-a s ispravcima od 21. 10. 2026.?
Česta pitanja
Kako se lozinke u PHP-u ispravno spremaju?
Pomoću password_hash() i PASSWORD_DEFAULT, a provjerava se s password_verify(). Stupac u bazi podataka prema priručniku treba primiti do 255 znakova jer se zadani algoritam u budućnosti može promijeniti.
Je li rand() prikladan za tokene?
Ne. Za tokene, ključeve i poveznice za lozinke treba koristiti random_bytes() ili random_int(). Prema priručniku daju kriptografski sigurne slučajne vrijednosti.
Otkad je Sodium uključen u PHP?
Ekstenzija Sodium za modernu kriptografiju dio je PHP-a od verzije 7.2.0. Starije verzije mogle su je dodati samo putem PECL-a.
Štite li te funkcije od PHP2Shella?
Ne. Štite od pogrešaka u Vašoj aplikaciji. PHP2Shell je u samom interpreteru i zatvara se samo PHP ažuriranjem, nakon čega slijedi ponovno pokretanje svih PHP procesa.
Mijenjaju li se zadane postavke sesija u PHP-u 8.6?
Da, prema prihvaćenom RFC-u session.use_strict_mode i session.cookie_httponly prema zadanim se postavkama uključuju, a session.cookie_samesite postavlja se na Lax. Postojeće konfiguracije ipak biste trebali sami izričito postaviti.