# Ugrađene sigurnosne funkcije PHP-a

> Pregled PHP sigurnosnih funkcija: lozinke, slučajnost, maskiranje, kriptografija, sesije i gdje su im granice kod ranjivosti poput PHP2Shella.

Izvor: https://phpsos.de/hr/php/eingebaute-sicherheitsfunktionen/  
Stanje: 25.10.2026  
Pružatelj: PHP SOS, PHP hitna pomoć i sigurnost poslužitelja. Hitna pomoć putem WhatsAppa: https://wa.me/491736494914?text=Pozdrav%20PHP%20SOS%2C%20trebamo%20pomo%C4%87%20s%20na%C5%A1im%20PHP%20poslu%C5%BEiteljem.%20Tvrtka%3A%20%E2%80%A6%20Web-stranica%3A%20%E2%80%A6

**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
<?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](https://phpsos.de/hr/blog/passwoerter-in-php-speichern/) i [sigurni slučajni brojevi i tokeni](https://phpsos.de/hr/blog/sichere-tokens-php/).

## 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
<?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](https://phpsos.de/hr/ratgeber/xss-php/) 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
<?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.

```ini
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](https://phpsos.de/hr/ratgeber/session-sicherheit-php/).

## Š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](https://phpsos.de/hr/leistungen/sicherheitsaudit-penetrationstest/) ciljano provjeravamo:

- **Postupanje s lozinkama i tokenima:** Koriste li se `password_hash()` i `random_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.

## Izvori

- [PHP priručnik: password_hash()](https://www.php.net/manual/en/function.password-hash.php)
- [PHP priručnik: random_bytes()](https://www.php.net/manual/en/function.random-bytes.php)
- [PHP priručnik: hash_equals()](https://www.php.net/manual/en/function.hash-equals.php)
- [PHP RFC: Secure Session Configuration Defaults](https://wiki.php.net/rfc/session_security_defaults)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
