Röviden: Az XSS-t PHP-ban úgy előzi meg, hogy minden kimenetet a környezetének megfelelően kódol: htmlspecialchars() a HTML-hez, json_encode() védelmi opciókkal a JavaScripthez, ellenőrzött URL-ek a linkekhez. Az automatikus escape-elésű sablonok ennek sokat levesznek a válláról. A Content Security Policy és a HttpOnly cookie-k korlátozzák a kárt arra az esetre, ha mégis marad rés.
Miért érdemes most a Cross-Site Scriptinget is ellenőrizni
2026 októberében a figyelem a PHP2Shellre irányul, a PHP-értelmezőben lévő két kritikus résre, amelyekhez 2026. 10. 21. óta állnak rendelkezésre javítások. Sok vállalkozás ennek keretében ellenőrizteti a webalkalmazásait. Ez jó alkalom arra is, hogy megnézze a saját kódban lévő sebezhetőségeket, amelyeket nem old meg egyetlen PHP-frissítés sem.
A Cross-Site Scripting, röviden XSS, ezek egyike. Az OWASP Top 10 az XSS-t az Injection kategórián belül tartja számon. A szerveren lévő réstől eltérően itt a támadás a weboldala látogatói és felhasználói ellen irányul, például a webshop ügyfelei vagy az admin felület munkatársai ellen.
A következmények jelentősek lehetnek: átvett rendszergazdai munkamenetek, manipulált űrlapok, amelyek adatokat küldenek harmadik félnek, vagy hamisított tartalmak a weboldalán. Ha egy rendszergazdai fiókot átvesznek, az az alkalmazás feletti teljes uralomig vezethet.
Hogyan keletkezik az XSS PHP-alkalmazásokban?
Az XSS akkor keletkezik, ha egy alkalmazás egy megbízhatatlan forrásból származó adatokat ellenőrzés nélkül ad ki egy oldalon. A böngésző ekkor már nem tud különbséget tenni az Ön tartalmai és a bejuttatott kód között, és mindkettőt végrehajtja.
Három formát különböztetnek meg. A reflektált XSS-nél a tartalom közvetlenül az aktuális kérésből származik, például az URL-ben lévő keresőkifejezésből. A tárolt XSS-nél az adatbázisban van, például egy hozzászólásban vagy profilmezőben, és mindenkit elér, aki az oldalt meghívja. A DOM-alapú XSS a böngésző JavaScriptjében keletkezik, amikor a szkriptek az URL-ből származó értékeket írnak az oldalba.
Megbízhatatlan minden adat, amely nem fixen áll a kódban: űrlapmezők, URL-paraméterek, cookie-k, fájlnevek, külső interfészek válaszai és a saját adatbázis tartalmai, amelyek valamikor kívülről érkeztek.
A kimenet helyes kódolása környezetenként
A legfontosabb szabály: kódoljon a kimenetnél, és pedig ahhoz a helyhez illően, ahová az érték kerül. HTML-tartalomhoz és idézőjelek közötti attribútumokhoz a htmlspecialchars() a választandó eszköz. Egy kis segédfüggvény megakadályozza, hogy az opciók elfelejtődjenek:
<?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'] ?? '') ?>">
Más környezetekhez más eszközök kellenek:
| Környezet | Biztonságos módszer |
|---|---|
| HTML-tartalom, idézőjelek közötti attribútum | htmlspecialchars() ENT_QUOTES kapcsolóval és UTF-8-cal |
| Adatok JavaScripthez | json_encode() a JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_HEX_QUOT kapcsolókkal |
| Paraméter egy URL-ben | rawurlencode() az egyes értékre |
| Teljes URL felhasználói bevitelből | a séma ellenőrzése, csak https és http engedélyezése, majd htmlspecialchars() |
| Idézőjel nélküli attribútumok, eseménykezelők, CSS | kerülje, ott ne illesszen be értékeket |
Egy szkript által igényelt adatokhoz többnyire egy adatattribútum vagy egy JSON-blokk a legtisztább út:
<?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>
A JavaScriptben az értéket ezután az adatattribútumon keresztül olvassa ki, a tartalmakat pedig textContent-tel, nem innerHTML-lel állítsa be.
Sablonok, HTML-tisztítás és keretrendszerek
Az olyan sablonmotorok, mint a Twig és a Blade, alapértelmezetten automatikusan kódolják a kimeneteket. Ez a tipikus hibák nagy részét kizárja. Veszélyessé ott válik, ahol ezt a viselkedést tudatosan kikapcsolják, például a Twigben a raw szűrővel vagy a Bladében a {!! !!} szintaxissal. Az ilyen helyeknek ritkáknak kell lenniük a kódban, és minden review-nál célzottan ellenőrizni kell őket.
Ha az alkalmazása tudatosan engedi a felhasználók HTML-jét, például formázásokat a hozzászólásokban vagy egy szerkesztőségi rendszerben, a kódolás nem elég, mert a HTML-t ugyanis meg kell jeleníteni. Ekkor ellenőrzött tisztító könyvtárra van szükség, például a HTML Purifierre, amely csak az engedélyezett elemek és attribútumok rögzített listáját engedi át. A reguláris kifejezésekkel készült saját szűrők tapasztalat szerint hiányosak.
Különösen az admin területeket ellenőrizze. Az XSS-t azokban a nézetekben, amelyeket csak rendszergazdák látnak, gyakran alábecsülik, pedig éppen a legtöbb joggal rendelkező fiókokat éri.
XSS keresése a meglévő PHP-kódban
A kialakult alkalmazásokban az első kérdés többnyire nem az, hogyan kell helyesen kódolni, hanem hogy hol felejtették el eddig. Pragmatikus kezdet azoknak a helyeknek a keresése, ahol a változókat közvetlenül adják ki:
# Kérésadatok közvetlen kiadása
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Kikapcsolt automatikus escape-elés Twigben és Bladében
grep -rnE "\|raw|\{!!" templates/ resources/views/
A találatok vizsgálati feladatok, nem kész megállapítások. A tárolt XSS-t egy ilyen keresés csak korlátozottan találja meg, mert az értékek ott az adatbázisból jönnek. Ezért ellenőrizzen ezen felül minden olyan nézetet, amely felhasználók tartalmait jeleníti meg: hozzászólások, profilok, rendelési megjegyzések, támogatási jegyek. CMS-eknél és webshopoknál a harmadik felek bővítményei és témái kifejezetten idetartoznak, mert a kimeneti logika nagy része ott van.
Második védvonal: CSP és biztonságos cookie-k
Gondos kód mellett is előfordulhat, hogy egy helyet átnéznek. Két intézkedés ekkor korlátozza a kárt. A Content Security Policy csak meghatározott forrásokból engedélyez szkripteket a böngészőnek, és tiltja a beágyazott szkripteket, amennyiben nincsenek kifejezetten engedélyezve:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
Egy ilyen irányelvet fokozatosan vezessen be, először tisztán jelentési módban a Content-Security-Policy-Report-Only fejlécen keresztül, mert az elemző vagy fizetési szolgáltatások meglévő beágyazásait többnyire ki kell egészíteni. További fejléceket a Biztonsági fejlécek weboldalakhoz útmutató ír le.
Emellett a munkamenet-cookie-knak viselniük kell a HttpOnly attribútumot, hogy a szkriptek ne tudják kiolvasni őket. Hogyan védheti a munkameneteket egészében, azt a Munkamenetek védelme PHP-ban útmutató írja le. Egy rokon, az adatbázis oldalán lévő sebezhetőséggel az SQL-injection megelőzése PHP-ban foglalkozik.
Hogyan segít konkrétan a PHP SOS?
- Ellenőrizzük az alkalmazása sablonjait és kimeneteit hiányzó vagy hibás kódolás szempontjából.
- A leleteket az elérhetőség és az érintett fiókok szerint értékeljük, és konkrét javításokat mutatunk.
- Fokozatosan bevezetünk egy Content Security Policyt, a webshop- vagy fizetési funkciók zavarása nélkül.
- A javítás után újra tesztelünk, és dokumentáljuk az eredményt.
Egy független ellenőrzést a Biztonsági audit és penetrációs teszt szolgáltatás ír le.
Gyakori kérdések
Elég a htmlspecialchars az XSS ellen?
Normál szövegre a HTML-tartalomban és idézőjelek közötti attribútumokban igen, ha megadja az ENT_QUOTES kapcsolót és az UTF-8 karakterkészletet. JavaScriptben, URL-ekben vagy CSS-ben más szabályok érvényesek, ott saját, megfelelő kódolásra van szükség.
A bemeneteket tároláskor vagy kimenetkor szűrjem?
Kódoljon a kimenetnél, a célnak megfelelően. A bemeneteket fogadáskor a hihetőségükre ellenőrizze, például a hosszra és a formátumra. Aki csak tároláskor szűr, figyelmen kívül hagyja a más forrásokból származó adatokat, és megnehezíti a későbbi felhasználást más környezetekben.
Mit ad egy Content Security Policy?
A Content Security Policy meghatározza, mely forrásokból tölthet be és futtathat szkripteket a böngésző. Egy figyelmen kívül hagyott XSS-rés hatásait jelentősen korlátozhatja, de a helyes kódolást nem pótolja.
Hogyan engedélyezzem a formázásokat, például a félkövért vagy a linkeket a hozzászólásokban?
Használjon ellenőrzött HTML-tisztító könyvtárat az engedélyezett elemek és attribútumok engedélylistájával. A szkriptek eltávolítására szolgáló saját reguláris kifejezések hibára hajlamosak, és nem szabad használni őket.