# Zabrániť XSS v PHP: bezpečne odraziť Cross-Site-Scripting

> Zabrániť XSS v PHP: správne kódovať výstupy podľa kontextu, používať šablóny s auto-escapingom a nastaviť Content Security Policy. S ukážkami.

Zdroj: https://phpsos.de/sk/ratgeber/xss-php/  
Stav: 25.10.2026  
Poskytovateľ: PHP SOS, Núdzová pomoc pri PHP a bezpečnosť serverov. Okamžitá pomoc cez WhatsApp: https://wa.me/491736494914?text=Dobr%C3%BD%20de%C5%88%2C%20PHP%20SOS%2C%20potrebujeme%20pomoc%20s%20na%C5%A1%C3%ADm%20serverom%20s%20PHP.%20Spolo%C4%8Dnos%C5%A5%3A%20%E2%80%A6%20Web%3A%20%E2%80%A6

**Stručne:** XSS v PHP zabránite tak, že každý výstup kódujete podľa jeho kontextu: `htmlspecialchars()` pre HTML, `json_encode()` s ochrannými voľbami pre JavaScript, preverené URL pre odkazy. Šablóny s automatickým escapingom vám z toho veľa odoberú. Content Security Policy a cookies HttpOnly obmedzujú škodu, ak nejaká zraniteľnosť predsa zostane.

## Prečo by sa mal Cross-Site-Scripting teraz skontrolovať tiež

Pozornosť je v októbri 2026 upriamená na PHP2Shell, dve kritické zraniteľnosti v interpreteri PHP, pre ktoré existujú záplaty od 21. 10. 2026. Mnohé podniky si v tejto súvislosti nechávajú preveriť svoje webové aplikácie. To je dobrá príležitosť pozrieť sa aj na slabiny vo vlastnom kóde, ktoré žiadna aktualizácia PHP neodstráni.

Cross-Site-Scripting, skrátene XSS, je jednou z nich. OWASP Top 10 vedie XSS v rámci kategórie Injection. Na rozdiel od zraniteľnosti na serveri smeruje útok tu proti návštevníkom a používateľom vášho webu, napríklad proti zákazníkom v e-shope alebo zamestnancom v backende.

Následky môžu byť značné: prevzaté relácie administrátorov, zmanipulované formuláre, ktoré posielajú údaje tretím stranám, alebo sfalšovaný obsah na vašom webe. Ak sa prevezme administrátorský účet, môže to viesť až k úplnej kontrole nad aplikáciou.

## Ako vzniká XSS v aplikáciách PHP?

XSS vzniká, keď aplikácia vypisuje údaje z nedôveryhodného zdroja na stránku bez kontroly. Prehliadač potom nevie rozlíšiť medzi vaším obsahom a zavlečeným kódom a vykoná oboje.

Rozlišujú sa tri formy. Pri reflektovanom XSS pochádza obsah priamo z aktuálnej požiadavky, napríklad z hľadaného výrazu v URL. Pri uloženom XSS leží v databáze, napríklad v komentári alebo poli profilu, a zasiahne každého, kto stránku otvorí. XSS založené na DOM vzniká v JavaScripte prehliadača, keď skripty zapisujú hodnoty z URL do stránky.

Nedôveryhodné sú všetky údaje, ktoré nie sú pevne v kóde: polia formulárov, parametre URL, cookies, názvy súborov, odpovede externých rozhraní a obsah z vlastnej databázy, ktorý niekedy prišiel zvonku.

## Správne kódovať výstup podľa kontextu

Najdôležitejšie pravidlo znie: kódovať pri výstupe, a to podľa miesta, kde hodnota pristane. Pre obsah HTML a atribúty v úvodzovkách je prostriedkom voľby `htmlspecialchars()`. Malá pomocná funkcia bráni zabudnutiu volieb:

```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'] ?? '') ?>">
```

Iné kontexty vyžadujú iné prostriedky:

| Kontext | Bezpečná metóda |
|---|---|
| Obsah HTML, atribút v úvodzovkách | `htmlspecialchars()` s `ENT_QUOTES` a UTF-8 |
| Údaje pre JavaScript | `json_encode()` s `JSON_HEX_TAG`, `JSON_HEX_AMP`, `JSON_HEX_APOS`, `JSON_HEX_QUOT` |
| Parameter v URL | `rawurlencode()` pre jednotlivú hodnotu |
| Úplná URL zo vstupu používateľa | Skontrolovať schému, povoliť len `https` a `http`, potom `htmlspecialchars()` |
| Atribúty bez úvodzoviek, obsluhy udalostí, CSS | vyhnúť sa, hodnoty tam nevkladať |

Pre údaje, ktoré potrebuje skript, je dátový atribút alebo blok JSON zvyčajne najčistejšou cestou:

```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 JavaScripte potom hodnotu načítate cez dátový atribút a obsah nastavujete pomocou `textContent` namiesto `innerHTML`.

## Šablóny, čistenie HTML a frameworky

Šablónové nástroje ako Twig a Blade kódujú výstupy štandardne automaticky. To vylučuje veľkú časť typických chýb. Nebezpečné je to tam, kde sa toto správanie vedome vypína, napríklad filtrom `raw` v Twig alebo syntaxou `{!! !!}` v Blade. Také miesta by mali byť v kóde zriedkavé a pri každom review sa cielene kontrolovať.

Ak má vaša aplikácia vedome povoliť HTML od používateľov, napríklad formátovanie v komentároch alebo v redakčnom systéme, kódovanie nestačí, pretože HTML sa má zobraziť. Potom potrebujete preverenú knižnicu na čistenie, ako je HTML Purifier, ktorá prepustí iba pevný zoznam povolených prvkov a atribútov. Vlastné filtre s regulárnymi výrazmi sú podľa skúseností dierave.

> **Dôležité:**
> Skontrolujte najmä oblasti backendu. XSS v zobrazeniach, ktoré vidia iba administrátori, sa často podceňuje, no zasahuje práve účty s najviac právami.

## Nájsť XSS v existujúcom kóde PHP

V rozrastených aplikáciách nie je prvou otázkou zvyčajne to, ako správne kódovať, ale kde sa to doteraz zabudlo. Pragmatickým začiatkom je hľadanie miest, kde sa premenné vypisujú priamo:

```bash
# Priame výpisy údajov požiadavky
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Vypnutý auto-escaping v Twig a Blade
grep -rnE "\|raw|\{!!" templates/ resources/views/
```

Nálezy sú úlohy na preverenie, nie hotové zistenia. Uložené XSS takéto hľadanie nájde len čiastočne, pretože hodnoty tam pochádzajú z databázy. Preto navyše skontrolujte všetky zobrazenia, ktoré ukazujú obsah od používateľov: komentáre, profily, poznámky k objednávkam, tikety podpory. Pri CMS a e-shopoch k tomu výslovne patria pluginy a témy tretích strán, pretože tam sídli veľká časť logiky výstupu.

## Druhá obranná línia: CSP a bezpečné cookies

Aj pri starostlivom kóde sa môže niektoré miesto prehliadnuť. Dve opatrenia potom obmedzujú škodu. Content Security Policy povolí prehliadaču iba skripty z určených zdrojov a zakáže vložené skripty, pokiaľ nie sú výslovne uvoľnené:

```apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
```

Takúto politiku zavádzajte postupne, najprv v čisto hlásnom režime cez `Content-Security-Policy-Report-Only`, pretože existujúce zapojenia analytických alebo platobných služieb sa zvyčajne musia doplniť. Ďalšie hlavičky popisuje príručka [Bezpečnostné hlavičky pre weby](https://phpsos.de/sk/ratgeber/sicherheits-header/).

Navyše by cookies relácie mali mať atribút `HttpOnly`, aby ich skripty nemohli vyčítať. Ako zabezpečiť session ako celok, je v príručke [Zabezpečiť session v PHP](https://phpsos.de/sk/ratgeber/session-sicherheit-php/). Príbuznú slabinu na strane databázy rieši príručka [Zabrániť SQL injection v PHP](https://phpsos.de/sk/ratgeber/sql-injection-php/).

## Ako konkrétne pomáha PHP SOS?

- Šablóny a výstupy vašej aplikácie kontrolujeme na chýbajúce alebo nesprávne kódovanie.
- Nálezy posudzujeme podľa dosiahnuteľnosti a dotknutých účtov a ukazujeme konkrétne opravy.
- Content Security Policy zavádzame postupne, bez rušenia funkcií e-shopu alebo platieb.
- Po oprave znova testujeme a výsledok zdokumentujeme.

Nezávislú kontrolu popisuje služba [Bezpečnostný audit a penetračný test](https://phpsos.de/sk/leistungen/sicherheitsaudit-penetrationstest/).


## Časté otázky

**Stačí htmlspecialchars proti XSS?**  
Pre bežný text v obsahu HTML a v atribútoch v úvodzovkách áno, ak uvediete ENT_QUOTES a znakovú sadu UTF-8. V JavaScripte, v URL alebo v CSS platia iné pravidlá, tam je potrebné vlastné, vhodné kódovanie.

**Mal by som vstupy filtrovať pri ukladaní alebo pri výstupe?**  
Kódujte pri výstupe, podľa cieľa. Vstupy by ste mali pri prijatí kontrolovať na prijateľnosť, napríklad dĺžku a formát. Kto filtruje iba pri ukladaní, prehliadne údaje z iných zdrojov a sťaží neskoršie použitie v iných kontextoch.

**Čo prináša Content Security Policy?**  
Content Security Policy určuje, z ktorých zdrojov smie prehliadač načítavať a vykonávať skripty. Môže výrazne obmedziť dosah prehliadnutej zraniteľnosti XSS, ale nenahrádza správne kódovanie.

**Ako povolím formátovanie ako tučné písmo alebo odkazy v komentároch?**  
Použite preverenú knižnicu na čistenie HTML s whitelistom povolených prvkov a atribútov. Vlastné regulárne výrazy na odstraňovanie skriptov sú náchylné na chyby a nemali by sa používať.

## Zdroje

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [php.net: bezpečnostné hlásenia](https://www.php.net/)
