# Preprečevanje XSS v PHP: zanesljiva obramba pred Cross-Site Scriptingom

> Preprečevanje XSS v PHP: izpise kodirajte glede na kontekst, uporabljajte predloge s samodejnim escapingom in nastavite Content Security Policy.

Vir: https://phpsos.de/sl/ratgeber/xss-php/  
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:** XSS v PHP preprečite tako, da vsak izpis kodirate glede na njegov kontekst: `htmlspecialchars()` za HTML, `json_encode()` z zaščitnimi možnostmi za JavaScript, preverjene URL-je za povezave. Predloge s samodejnim escapingom vam veliko tega prevzamejo. Content Security Policy in piškotki HttpOnly omejijo škodo, če ranljivost vendarle ostane.

## Zakaj naj zdaj preverite tudi Cross-Site Scripting

Pozornost je oktobra 2026 usmerjena v PHP2Shell, dve kritični ranljivosti v interpreterju PHP, za kateri so popravki na voljo od 21. 10. 2026. Številna podjetja v tem zamahu dajo pregledati svoje spletne aplikacije. To je dobra priložnost, da se pogleda tudi šibkosti v lastni kodi, ki jih nobena posodobitev PHP ne odpravi.

Cross-Site Scripting, na kratko XSS, je ena od njih. OWASP Top 10 XSS vodi znotraj kategorije Injection. Za razliko od ranljivosti na strežniku je napad tu usmerjen proti obiskovalcem in uporabnikom vaše spletne strani, na primer proti strankam v trgovini ali zaposlenim v zaledju.

Posledice so lahko hude: prevzete seje skrbnikov, manipulirani obrazci, ki podatke pošiljajo tretjim osebam, ali ponarejene vsebine na vaši spletni strani. Če je prevzet skrbniški račun, lahko to vodi do popolnega nadzora nad aplikacijo.

## Kako nastane XSS v aplikacijah PHP?

XSS nastane, ko aplikacija podatke iz nezaupanja vrednega vira nepreverjene izpiše na stran. Brskalnik potem ne more več razlikovati med vašimi vsebinami in vneseno kodo in izvede oboje.

Ločimo tri oblike. Pri odbitem XSS vsebina izvira neposredno iz tekoče zahteve, na primer iz iskalnega pojma v URL. Pri shranjenem XSS leži v podatkovni zbirki, na primer v komentarju ali polju profila, in zadene vsakogar, ki stran odpre. XSS, ki temelji na DOM, nastane v JavaScriptu brskalnika, ko skripte vrednosti iz URL zapišejo na stran.

Nezaupanja vredni so vsi podatki, ki niso trdno zapisani v kodi: polja obrazcev, parametri URL, piškotki, imena datotek, odgovori zunanjih vmesnikov in vsebine iz lastne podatkovne zbirke, ki so nekoč prišle od zunaj.

## Pravilno kodiranje izpisa glede na kontekst

Najpomembnejše pravilo se glasi: kodirajte ob izpisu, in sicer ustrezno kraju, kjer vrednost pristane. Za vsebino HTML in atribute v narekovajih je sredstvo izbire `htmlspecialchars()`. Majhna pomožna funkcija preprečuje, da bi se možnosti pozabile:

```php
<?php
function e(?string $wert): string
{
    return htmlspecialchars($wert ?? '', ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
?>
<h2><?= e($produkt['name']) ?></h2>
<input type="text" name="suche" value="<?= e($_GET['q'] ?? '') ?>">
```

Drugi konteksti zahtevajo druga sredstva:

| Kontekst | Varna metoda |
|---|---|
| Vsebina HTML, atribut v narekovajih | `htmlspecialchars()` z `ENT_QUOTES` in UTF-8 |
| Podatki za JavaScript | `json_encode()` z `JSON_HEX_TAG`, `JSON_HEX_AMP`, `JSON_HEX_APOS`, `JSON_HEX_QUOT` |
| Parameter v URL | `rawurlencode()` za posamezno vrednost |
| Celoten URL iz uporabniškega vnosa | Preverite shemo, dovolite samo `https` in `http`, nato `htmlspecialchars()` |
| Atributi brez narekovajev, obravnavalniki dogodkov, CSS | izogibajte se, vrednosti tam ne vstavljajte |

Za podatke, ki jih skripta potrebuje, je atribut data ali blok JSON običajno najčistejša pot:

```php
<?php
$daten = json_encode($konfiguration, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>
<div id="app" data-konfig="<?= e($daten) ?>"></div>
```

V JavaScriptu vrednost nato preberete prek atributa data in vsebine nastavite s `textContent` namesto z `innerHTML`.

## Predloge, čiščenje HTML in ogrodja

Mehanizmi predlog, kot sta Twig in Blade, izpise privzeto kodirajo samodejno. To izključi velik del tipičnih napak. Nevarno postane tam, kjer je to obnašanje zavestno izklopljeno, na primer s filtrom `raw` v Twigu ali s sintakso `{!! !!}` v Bladeu. Takšna mesta bi morala biti v kodi redka in jih je treba ob vsakem pregledu ciljno preveriti.

Če naj vaša aplikacija zavestno dopušča HTML uporabnikov, na primer oblikovanje v komentarjih ali v uredniškem sistemu, kodiranje ne zadošča, ker naj se HTML prikaže. Tedaj potrebujete preverjeno knjižnico za čiščenje, kot je HTML Purifier, ki prepusti samo trden seznam dovoljenih elementov in atributov. Lastni filtri z regularnimi izrazi so po izkušnjah luknjasti.

> **Pomembno:**
> Posebej preverite območja zaledja. XSS v pogledih, ki jih vidijo samo skrbniki, se pogosto podcenjuje, a zadene ravno račune z največ pravicami.

## Iskanje XSS v obstoječi kodi PHP

Pri zraslih aplikacijah prvo vprašanje običajno ni, kako pravilno kodirati, ampak kje je bilo to doslej pozabljeno. Pragmatičen začetek je iskanje mest, kjer se spremenljivke izpisujejo neposredno:

```bash
# Neposredni izpisi podatkov zahteve
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Izklopljen samodejni escaping v Twigu in Bladeu
grep -rnE "\|raw|\{!!" templates/ resources/views/
```

Zadetki so naloge za preverjanje, ne dokončne ugotovitve. Shranjeni XSS takšno iskanje najde le omejeno, ker vrednosti tam prihajajo iz podatkovne zbirke. Zato dodatno preverite vse poglede, ki prikazujejo vsebine uporabnikov: komentarje, profile, opombe k naročilom, prijave na podporo. Pri CMS-jih in trgovinah izrecno sodijo zraven vtičniki in teme tretjih ponudnikov, saj je tam velik del izpisne logike.

## Druga obrambna linija: CSP in varni piškotki

Tudi pri skrbni kodi je mogoče kakšno mesto spregledati. Dva ukrepa nato omejita škodo. Content Security Policy brskalniku dovoli samo skripte iz določenih virov in prepove vdelane skripte, če niso izrecno odobrene:

```apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
```

Takšno pravilo uvajajte postopoma, najprej samo v načinu poročanja prek `Content-Security-Policy-Report-Only`, saj je obstoječe vključitve storitev za analitiko ali plačila praviloma treba dopolniti. Dodatne glave opisuje vodnik [Varnostne glave za spletne strani](https://phpsos.de/sl/ratgeber/sicherheits-header/).

Poleg tega naj imajo piškotki sej atribut `HttpOnly`, da jih skripte ne morejo prebrati. Kako sej zaščitite v celoti, piše v vodniku [Zaščita sej v PHP](https://phpsos.de/sl/ratgeber/session-sicherheit-php/). Sorodno ranljivost na strani podatkovne zbirke obravnava vodnik [Preprečevanje SQL injection v PHP](https://phpsos.de/sl/ratgeber/sql-injection-php/).

## Kako PHP SOS pomaga konkretno?

- Predloge in izpise vaše aplikacije preverimo glede manjkajočega ali napačnega kodiranja.
- Najdbe ocenimo glede na dosegljivost in prizadete račune ter pokažemo konkretne popravke.
- Content Security Policy uvedemo postopoma, ne da bi motili funkcije trgovine ali plačil.
- Po popravku ponovno preizkusimo in rezultat dokumentiramo.

Neodvisno preverjanje opisuje storitev [Varnostni pregled in penetracijski test](https://phpsos.de/sl/leistungen/sicherheitsaudit-penetrationstest/).


## Pogosta vprašanja

**Ali htmlspecialchars zadošča proti XSS?**  
Za navadno besedilo v vsebini HTML in v atributih v narekovajih da, če navedete ENT_QUOTES in nabor znakov UTF-8. V JavaScriptu, v URL-jih ali v CSS veljajo drugačna pravila, tam je potrebno lastno, ustrezno kodiranje.

**Ali naj vnose filtriram ob shranjevanju ali ob izpisu?**  
Kodirajte ob izpisu, glede na cilj. Vnose ob prejemu preverite glede verjetnosti, na primer dolžine in oblike. Kdor filtrira samo ob shranjevanju, spregleda podatke iz drugih virov in otežuje poznejšo uporabo v drugih kontekstih.

**Kaj prinese Content Security Policy?**  
Content Security Policy določa, iz katerih virov sme brskalnik nalagati in izvajati skripte. Posledice spregledane ranljivosti XSS lahko občutno omeji, vendar pravilnega kodiranja ne nadomesti.

**Kako dovolim oblikovanje, kot je krepko ali povezave, v komentarjih?**  
Uporabite preverjeno knjižnico za čiščenje HTML s seznamom dovoljenih elementov in atributov. Lastni regularni izrazi za odstranjevanje skript so dovzetni za napake in se jih ne sme uporabljati.

## Viri

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [php.net: varnostna obvestila](https://www.php.net/)
