# Vgrajene varnostne funkcije PHP

> Varnostne funkcije PHP na kratko: gesla, naključnost, maskiranje, kriptografija, seje ter meje teh funkcij pri vrzelih, kot je PHP2Shell.

Vir: https://phpsos.de/sl/php/eingebaute-sicherheitsfunktionen/  
Stanje: 25.10.2026  
Ponudnik: PHP SOS, Nujna pomoč za PHP in varnost strežnikov. Takojšnja pomoč po WhatsAppu: https://wa.me/491736494914?text=Pozdravljeni%2C%20PHP%20SOS%2C%20potrebujemo%20pomo%C4%8D%20z%20na%C5%A1im%20stre%C5%BEnikom%20PHP.%20Podjetje%3A%20%E2%80%A6%20Spletna%20stran%3A%20%E2%80%A6

**Na kratko:** PHP za najpogostejše varnostne naloge prinaša že pripravljene, preverjene funkcije: `password_hash()` za gesla, `random_bytes()` in `random_int()` za žetone, `htmlspecialchars()` proti cross-site scriptingu, pripravljene poizvedbe s PDO proti SQL injection, `hash_equals()` za varne primerjave in razširitev Sodium za kriptografijo. Kdor te gradnike dosledno uporablja, se izogne večini vrzeli v aplikacijah. Proti napakam v samem interpreterju PHP, kot pri PHP2Shell, ne pomagajo; tam pomaga samo posodobitev.

## Zakaj vgrajene varnostne funkcije PHP?

Pisanje varnostne kode samemu je nagnjeno k napakam. Lasten zgoščevalnik gesel, domač generator žetonov ali doma spletena sita za izpise HTML pogosto izgledajo pravilno, pa niso. Vgrajene funkcije so dokumentirane, preizkušene in se vzdržujejo s posodobitvami PHP.

Za odločevalce to pomeni: svoje agencije ali razvojne ekipe ne vprašajte, ali so bile varnostne funkcije napisane same, temveč ali se uporabljajo standardne funkcije jezika. Tabela daje pregled.

| Naloga | Funkcija | Na voljo od | Pomemben namig |
|---|---|---|---|
| Shranjevanje gesel | `password_hash()`, `password_verify()` | PHP 5.5 | stolpec do 255 znakov; bcrypt skrajša na 72 bajtov |
| Naključni žetoni | `random_bytes()`, `random_int()` | PHP 7.0 | nikoli `rand()` ali `mt_rand()` za skrivnosti |
| Naključnost objektno usmerjeno | `Random\Randomizer` | PHP 8.2 | enaka varnost, bolj prilagodljiv vmesnik |
| Maskiranje izpisa HTML | `htmlspecialchars()` | od nekdaj | privzete zastavice od 8.1 maskirajo tudi enojne narekovaje |
| Primerjava s konstantnim časom | `hash_equals()` | PHP 5.6 | uporabnikov vnos kot drugi argument |
| Sodobna kriptografija | Sodium (`sodium_*`) | PHP 7.2 | namesto lastnega šifriranja |
| Skrivnosti v sledeh klicev | `#[\SensitiveParameter]` | PHP 8.2 | vrednost se v sledi ne pojavi |
| Preverjanje vnosov | `filter_var()` | PHP 5.2 | preveri obliko, ne nadomesti maskiranja |

## Gesla in žetoni

`password_hash()` ustvari soljen zgoščevalnik, `password_verify()` ga preveri. S `PASSWORD_DEFAULT` PHP trenutno uporablja bcrypt; od PHP 8.4 je privzeti faktor stroška po priročniku 12 namesto 10. Ker se lahko privzeti algoritem spremeni, priročnik priporoča stolpec podatkovne baze s 255 znaki. Pri bcrypt se gesla po 72 bajtih odrežejo, kar je treba upoštevati pri zelo dolgih geslih v obliki stavkov.

```php
<?php
// Registracija
$hash = password_hash($passwort, PASSWORD_DEFAULT);

// Prijava, vključno s samodejno nadgradnjo starih zgoščenih vrednosti
if (password_verify($eingabe, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($eingabe, PASSWORD_DEFAULT); // shraniti znova
    }
}

// Žeton za povezavo za ponastavitev gesla
$token = bin2hex(random_bytes(32));
```

Za primerjave skrivnosti, na primer podpisa, je treba uporabiti `hash_equals()`. Običajna primerjava z `===` lahko po priročniku prek časa izvajanja izda, od katerega mesta se dve vrednosti razlikujeta. Podrobneje: [Varno shranjevanje gesel v PHP](https://phpsos.de/sl/blog/passwoerter-in-php-speichern/) in [varna naključna števila in žetoni](https://phpsos.de/sl/blog/sichere-tokens-php/).

## Maskiranje izpisov in varno poizvedovanje po podatkovni bazi

Cross-site scripting nastane, ko vnosi uporabnika nefiltrirani pristanejo v HTML. `htmlspecialchars()` posebne znake pretvori v entitete HTML. Od PHP 8.1 so privzete zastavice `ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401`; prej se enojni narekovaji niso pretvarjali. Kdor mora podpirati starejše različice, zastavice navede izrecno.

SQL injection preprečujejo pripravljene poizvedbe. Vrednosti se prenašajo ločeno od besedila SQL in poizvedbe ne morejo spremeniti:

```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');
```

Podrobnosti so pod [Preprečevanje cross-site scriptinga v PHP](https://phpsos.de/sl/ratgeber/xss-php/) in na strani o SQL injection.

Preverjanje vnosov je drugi, ločen korak. `filter_var()` ugotovi, ali ima vrednost veljavno obliko, na primer e-poštni naslov ali celo število v dovoljenem območju. To pa ne nadomesti maskiranja pri izpisu in ne pripravljene poizvedbe, saj lahko tudi formalno veljavne vrednosti vsebujejo posebne znake.

## Skrivnosti zadržati stran od sporočil o napakah

Premalo cenjeno uhajanje podatkov so sledi klicev (stack trace). Če v funkciji pride do napake, PHP zabeleži verigo klicev z argumenti. Če je tam geslo ali ključ API, pristane v dnevniku. Od PHP 8.2 atribut `#[\SensitiveParameter]` take parametre označi; njihova vrednost se v sledi nato pojavi samo kot objekt `SensitiveParameterValue`.

```php
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
    // ... preverjanje ...
    throw new RuntimeException('Datenbank nicht erreichbar');
}
```

Po opombi v priročniku atribut deluje samo pri konkretni implementaciji, ne pri metodi vmesnika. Zato ga nastavite tam, kjer koda dejansko teče.

## Seje: varne nastavitve in novi privzeti standardi

Seje so pogost cilj napadov. Tri nastavitve so osrednje: `session.use_strict_mode=1` zavrne ID-je sej, ki jih strežnik ni sam ustvaril; `session.cookie_httponly=1` prepreči dostop do piškotka seje prek JavaScripta; `session.cookie_samesite=Lax` otežuje sočasno pošiljanje pri tujih straneh. Po sprejetem RFC te tri vrednosti s PHP 8.6 postanejo privzete. Do takrat jih nastavite sami, in tudi potem izrecno, da konfiguracija ni odvisna od privzetih vrednosti.

```ini
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
```

Več o tem pod [Zavarovanje sej v PHP](https://phpsos.de/sl/ratgeber/session-sicherheit-php/).

## Česa vgrajene funkcije ne zmorejo

Projekt PHP je v svoji varnostni politiki jasen: PHP ni peskovnik (sandbox). Zaobhodi `open_basedir` ali `disable_functions`, zlonamerni vnosi v `unserialize()` in neprevereni argumenti v funkcijah, kot je `mysqli_query()`, se ne štejejo za varnostne vrzeli PHP. Za upravljavce to pomeni: te nastavitve so koristno utrjevanje, ne pa varnostna meja, `unserialize()` pa s tujimi podatki nima kaj početi.

Druga točka zadeva PHP2Shell. CVE-2026-109618 in CVE-2026-109619 po navedbah php.net omogočata izvedbo kode, preden ali medtem ko vaša aplikacija teče; pri mod_php je bil exploit prikazan, še preden se sploh izvede koda aplikacije. Nobena funkcija v vaši kodi tega ne more ujeti. Varno programiranje in aktualna različica PHP sta dve ločeni obveznosti in izpolnjeni morata biti obe.

## Kako PHP SOS pomaga konkretno?

V [varnostnem pregledu za aplikacije PHP](https://phpsos.de/sl/leistungen/sicherheitsaudit-penetrationstest/) ciljno preverimo:

- **Ravnanje z gesli in žetoni:** ali se uporabljata `password_hash()` in `random_bytes()`, ali obstajajo lastne izdelave?
- **Izpisi in poizvedbe:** kje vnosi nefiltrirani pristanejo v HTML, SQL ali ukaze lupine?
- **Konfiguracija sej:** ali so Strict Mode, HttpOnly, SameSite in Secure nastavljeni in jih ni mogoče prepisati?
- **Izvajalno okolje:** ali teče podprta različica PHP s popravki z dne 21. 10. 2026?


## Pogosta vprašanja

**Kako se v PHP pravilno shranjujejo gesla?**  
S password_hash() in PASSWORD_DEFAULT, preverja se s password_verify(). Stolpec podatkovne baze naj po priročniku sprejme do 255 znakov, ker se lahko privzeti algoritem v prihodnje spremeni.

**Ali je rand() primeren za žetone?**  
Ne. Za žetone, ključe in povezave za geslo je treba uporabiti random_bytes() ali random_int(). Po priročniku vračata kriptografsko varne naključne vrednosti.

**Od kdaj je Sodium vključen v PHP?**  
Razširitev Sodium za sodobno kriptografijo je del PHP od PHP 7.2.0. Starejše različice so jo lahko dodale samo prek PECL.

**Ali te funkcije ščitijo pred PHP2Shell?**  
Ne. Ščitijo pred napakami v vaši aplikaciji. PHP2Shell tiči v samem interpreterju in ga zapre samo posodobitev PHP, ki ji sledi ponovni zagon vseh procesov PHP.

**Ali se privzete nastavitve sej v PHP 8.6 spreminjajo?**  
Da, po sprejetem RFC se session.use_strict_mode in session.cookie_httponly privzeto vklopita, session.cookie_samesite pa se nastavi na Lax. Obstoječe konfiguracije kljub temu nastavite sami in izrecno.

## Viri

- [Priročnik PHP: password_hash()](https://www.php.net/manual/en/function.password-hash.php)
- [Priročnik PHP: random_bytes()](https://www.php.net/manual/en/function.random-bytes.php)
- [Priročnik PHP: 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/)
