SQL injection a XSS: jak se bránit

Dva nejstarší útoky na weby jsou pořád aktuální. Vysvětluji na kódu, jak SQL injection a XSS vznikají a jak se jim v Laravelu i čistém PHP spolehlivě bránit.
Publikováno 04.09.2026

SQL injection a XSS: jak se bránit

Publikováno

· Autor: · Pod kapotou · Bezpečnost · 3 min čtení

Obsah článku

SQL injection a XSS patří mezi nejstarší útoky na weby a přesto na ně narážím pořád. Oba figurují v žebříčcích nejčastějších zranitelností už roky a oba vznikají ze stejné chyby: aplikace slepě důvěřuje vstupu od uživatele. Dobrá zpráva je, že obrana proti oběma je jednoduchá, když víte, kde je slabina. Ukážu na kódu, jak vznikají a jak se jim v PHP i moderním frameworku jako Laravel spolehlivě bránit.

Jak vzniká SQL injection

SQL injection nastane, když uživatelský vstup skládáte přímo do databázového dotazu. Útočník pak místo jména pošle kousek SQL a ovládne databázi.

// ZRANITELNÉ: vstup jde přímo do dotazu
$email = $_GET['email'];
$sql = "SELECT * FROM users WHERE email = '$email'";
// Útočník pošle:  ' OR '1'='1
// a vrátí se mu všechny řádky

Obrana: parametrizované dotazy

Řešení je jednoduché — vstup nikdy nespojujte s dotazem, předávejte ho jako parametr. Laravel to přes Eloquent a query builder dělá za vás automaticky.

// Bezpečně přes Eloquent
$user = User::where('email', $request->email)->first();

// Bezpečně přes query builder s parametrem
$users = DB::select(
    'SELECT * FROM users WHERE email = ?',
    [$request->email]
);
  • Otazník je zástupný symbol, hodnota se doplní bezpečně.
  • Přes Eloquent se o parametrizaci nemusíte starat vůbec.
  • I u řazení a názvů sloupců hlídám, aby nešly přímo od uživatele.
  • Základní práci s modely popisuji v častých chybách začátečníků v Laravelu.

Pozor na jednu pastičku: parametry chrání hodnoty, ale ne názvy sloupců nebo směr řazení. Pokud tyhle části dotazu sestavujete z uživatelského vstupu, musíte je ověřit proti pevnému seznamu povolených hodnot, jinak si zaděláváte na stejný problém jinými dveřmi.

Jak vzniká XSS

Cross-site scripting nastane, když do stránky vypíšete neošetřený vstup a prohlížeč ho spustí jako kód. Útočník tak může krást přihlašovací údaje, číst obsah stránky nebo návštěvníka nenápadně přesměrovat na podvodný web. Zákeřné na tom je, že vstup nemusí přijít jen z formuláře — může být uložený v databázi z dřívějška a spustit se každému, kdo stránku otevře.

// ZRANITELNÉ v čistém PHP
echo "<p>" . $_GET['jmeno'] . "</p>";
// Útočník pošle:  <script>ukradniCookie()</script>

Obrana: escapování výstupu

Každý výstup, který pochází od uživatele, je potřeba escapovat. Blade v Laravelu to dělá u dvojitých složených závorek automaticky.

{{-- Blade escapuje automaticky --}}
<p>{{ $jmeno }}</p>

// V čistém PHP escapuj ručně
echo '<p>' . htmlspecialchars($jmeno, ENT_QUOTES) . '</p>';
  • Syntaxi {!! !!} používám jen na data, kterým opravdu věřím.
  • Vstup navíc validuji přes Form Request.

Ještě dodám jednu vrstvu navíc: hlavičky Content Security Policy dokážou omezit, co smí prohlížeč vůbec spustit, a tím XSS ztíží i v případě, že by se něco proklouzlo. Není to náhrada za escapování, ale pojistka navíc, kterou u citlivějších projektů rád nasazuji. Na jednoduchém webu je to naopak zbytečná komplikace, kterou byste jen udržovali.

Obě zranitelnosti nakonec odrazí jedno pravidlo: nikdy nevěřte vstupu a vždy ošetřete výstup. Když se ho držíte důsledně, máte devadesát procent práce hotovo. Chcete prověřit svůj kód? Napište mi na nezávaznou poptávku.