# Sprječavanje XSS-a u PHP-u: sigurna obrana od cross-site scriptinga

> Sprječavanje XSS-a u PHP-u: ispravno kodirajte izlaze po kontekstu, koristite predloške s auto-escapingom i postavite Content Security Policy. S primjerima.

Izvor: https://phpsos.de/hr/ratgeber/xss-php/  
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:** XSS u PHP-u sprječavate tako da svaki izlaz kodirate prema njegovu kontekstu: `htmlspecialchars()` za HTML, `json_encode()` sa zaštitnim opcijama za JavaScript, provjereni URL-ovi za poveznice. Predlošci s automatskim escapingom preuzimaju Vam velik dio toga. Content Security Policy i HttpOnly kolačići ograničavaju štetu ako ipak ostane ranjivost.

## Zašto bi cross-site scripting sada trebalo provjeriti uz ostalo

Pozornost je u listopadu 2026. na PHP2Shellu, dvjema kritičnim ranjivostima u PHP interpreteru, za koje od 21.10.2026. postoje zakrpe. Mnoge tvrtke tim povodom daju provjeriti svoje web-aplikacije. To je dobar povod da se pogledaju i slabosti u vlastitom kodu koje nijedno PHP ažuriranje ne otklanja.

Cross-site scripting, skraćeno XSS, jedna je od njih. OWASP Top 10 vodi XSS unutar kategorije Injection. Za razliku od ranjivosti na poslužitelju, napad je ovdje usmjeren protiv posjetitelja i korisnika Vaše web-stranice, primjerice klijenata u shopu ili zaposlenika u backendu.

Posljedice mogu biti znatne: preuzete sesije administratora, manipulirani obrasci koji šalju podatke trećima ili krivotvoreni sadržaji na Vašoj web-stranici. Ako se preuzme administratorski račun, to može dovesti do potpune kontrole nad aplikacijom.

## Kako nastaje XSS u PHP aplikacijama

XSS nastaje kad aplikacija podatke iz nepouzdanog izvora neprovjereno ispisuje na stranicu. Preglednik tada više ne može razlikovati Vaše sadržaje od ubačenog koda i izvršava oboje.

Razlikuju se tri oblika. Kod reflektiranog XSS-a sadržaj dolazi izravno iz aktualnog zahtjeva, primjerice iz pojma za pretragu u URL-u. Kod pohranjenog XSS-a nalazi se u bazi podataka, primjerice u komentaru ili polju profila, i pogađa svakoga tko otvori stranicu. DOM-based XSS nastaje u JavaScriptu preglednika kad skripte upisuju vrijednosti iz URL-a na stranicu.

Nepouzdani su svi podaci koji nisu čvrsto u kodu: polja obrazaca, URL parametri, kolačići, nazivi datoteka, odgovori vanjskih sučelja i sadržaji iz vlastite baze koji su u nekom trenutku došli izvana.

## Ispravno kodiranje izlaza po kontekstu

Najvažnije pravilo glasi: kodirajte pri izlazu, i to prema mjestu na kojem vrijednost završava. Za HTML sadržaj i atribute u navodnicima `htmlspecialchars()` je sredstvo izbora. Mala pomoćna funkcija sprječava da se opcije zaborave:

```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 trebaju druga sredstva:

| Kontekst | Sigurna metoda |
|---|---|
| HTML sadržaj, atribut u navodnicima | `htmlspecialchars()` s `ENT_QUOTES` i UTF-8 |
| Podaci za JavaScript | `json_encode()` s `JSON_HEX_TAG`, `JSON_HEX_AMP`, `JSON_HEX_APOS`, `JSON_HEX_QUOT` |
| Parametar u URL-u | `rawurlencode()` za pojedinačnu vrijednost |
| Potpuni URL iz korisničkog unosa | Provjeriti shemu, dopustiti samo `https` i `http`, zatim `htmlspecialchars()` |
| Atributi bez navodnika, event handleri, CSS | izbjegavati, tamo ne umetati vrijednosti |

Za podatke koje skripta treba, atribut podataka ili JSON blok obično je najčišći put:

```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>
```

U JavaScriptu vrijednost zatim čitate putem atributa podataka, a sadržaje postavljate s `textContent` umjesto s `innerHTML`.

## Predlošci, čišćenje HTML-a i frameworki

Template engineovi poput Twiga i Bladea po zadanim postavkama automatski kodiraju izlaze. To isključuje velik dio tipičnih pogrešaka. Opasno postaje tamo gdje se to ponašanje namjerno isključi, primjerice filtrom `raw` u Twigu ili sintaksom `{!! !!}` u Bladeu. Takvih bi mjesta u kodu trebalo biti malo i treba ih ciljano provjeriti pri svakom pregledu.

Ako Vaša aplikacija namjerno treba dopuštati HTML korisnika, primjerice formatiranje u komentarima ili u sustavu za uredništvo, kodiranje nije dovoljno jer HTML treba biti prikazan. Tada trebate provjerenu biblioteku za čišćenje poput HTML Purifiera, koja propušta samo čvrst popis dopuštenih elemenata i atributa. Vlastiti filtri s regularnim izrazima prema iskustvu su manjkavi.

> **Važno:**
> Posebno provjerite backend područja. XSS u prikazima koje vide samo administratori često se podcjenjuje, a pogađa upravo račune s najviše prava.

## Pronalaženje XSS-a u postojećem PHP kodu

U razvijenim aplikacijama prvo pitanje obično nije kako ispravno kodirati, nego gdje se to dosad zaboravilo. Pragmatičan početak je potraga za mjestima na kojima se varijable ispisuju izravno:

```bash
# Izravni ispisi podataka zahtjeva
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Isključen auto-escaping u Twigu i Bladeu
grep -rnE "\|raw|\{!!" templates/ resources/views/
```

Pogoci su zadaci za provjeru, a ne gotovi nalazi. Pohranjeni XSS takva pretraga pronalazi samo uvjetno jer vrijednosti tamo dolaze iz baze podataka. Zato dodatno provjerite sve prikaze koji prikazuju sadržaje korisnika: komentare, profile, bilješke narudžbi, tikete podrške. Kod CMS-ova i shopova dodaci i teme trećih strana izričito spadaju u to jer se tamo nalazi velik dio logike izlaza.

## Druga linija obrane: CSP i sigurni kolačići

Čak i uz pažljiv kod može se previdjeti jedno mjesto. Dvije mjere tada ograničavaju štetu. Content Security Policy pregledniku dopušta samo skripte iz određenih izvora i zabranjuje ugrađene skripte, osim ako nisu izričito odobrene:

```apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
```

Takvu politiku uvodite postupno, najprije u čistom načinu izvješćivanja putem `Content-Security-Policy-Report-Only`, jer postojeće ugradnje usluga analitike ili plaćanja obično treba dopuniti. Dodatna zaglavlja opisuje vodič [Sigurnosna zaglavlja za web-stranice](https://phpsos.de/hr/ratgeber/sicherheits-header/).

Uz to kolačići sesije trebaju imati atribut `HttpOnly` kako ih skripte ne bi mogle čitati. Kako osigurati sesije u cjelini, nalazi se u vodiču [Osiguravanje sesija u PHP-u](https://phpsos.de/hr/ratgeber/session-sicherheit-php/). Srodnu slabost na strani baze podataka obrađuje [Sprječavanje SQL injectiona u PHP-u](https://phpsos.de/hr/ratgeber/sql-injection-php/).

## Kako PHP SOS konkretno pomaže?

- Provjeravamo predloške i izlaze Vaše aplikacije na nedostajuće ili pogrešno kodiranje.
- Nalaze ocjenjujemo prema dostupnosti i pogođenim računima te pokazujemo konkretne ispravke.
- Content Security Policy uvodimo postupno, bez ometanja funkcija shopa ili plaćanja.
- Nakon ispravka ponovno testiramo i dokumentiramo rezultat.

Neovisnu provjeru opisuje usluga [Sigurnosni audit i penetracijski test](https://phpsos.de/hr/leistungen/sicherheitsaudit-penetrationstest/).


## Česta pitanja

**Je li htmlspecialchars dovoljan protiv XSS-a?**  
Za običan tekst u HTML sadržaju i u atributima u navodnicima da, ako navedete ENT_QUOTES i skup znakova UTF-8. U JavaScriptu, u URL-ovima ili u CSS-u vrijede druga pravila, tamo treba vlastito, prikladno kodiranje.

**Trebam li unose filtrirati pri spremanju ili pri izlazu?**  
Kodirajte pri izlazu, prema odredištu. Unose pri primitku provjerite na vjerodostojnost, primjerice duljinu i format. Tko filtrira samo pri spremanju, previđa podatke iz drugih izvora i otežava kasniju uporabu u drugim kontekstima.

**Što donosi Content Security Policy?**  
Content Security Policy određuje iz kojih izvora preglednik smije učitavati i izvršavati skripte. Može znatno ograničiti posljedice previđene XSS ranjivosti, ali ne zamjenjuje ispravno kodiranje.

**Kako dopustiti formatiranje poput podebljanog teksta ili poveznica u komentarima?**  
Koristite provjerenu biblioteku za čišćenje HTML-a s whitelistom dopuštenih elemenata i atributa. Vlastiti regularni izrazi za uklanjanje skripti podložni su pogreškama i ne bi ih trebalo koristiti.

## Izvori

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [php.net: sigurnosne objave](https://www.php.net/)
