Trenutno stanje: PHP2Shell. Dvije kritične PHP ranjivosti (CVSS 9.2) omogućuju zlonamjerni kod bez prijave. Zakrpe od 21. 10. 2026.Što sada učiniti →

Sprječavanje XSS-a u PHP-u: sigurna obrana od cross-site scriptinga

Kako programeri sprječavaju cross-site scripting u PHP aplikacijama: kodiranje prema kontekstu, auto-escaping u predlošcima, čišćenje HTML-a i Content Security Policy.

Stanje 5 min čitanjaSavjetnik

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
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
$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:

# 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:

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.

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. Srodnu slabost na strani baze podataka obrađuje Sprječavanje SQL injectiona u PHP-u.

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.

Č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

Hitni kontakt

Svaki sat se računa. Pišite nam odmah.

Ukratko opišite sustav, verziju PHP-a i opažanje. Javit ćemo Vam se, razjasniti situaciju i raditi na daljinu dok incident nije zaključen i dokumentiran.

Hitna pomoć