# Kontrola databáze na vložený kód

> Kontrola databáze na škodlivý kód: jak čtecími dotazy najít vložené skripty, cizí adresy, triggery a účty, aniž byste zničili data.

Zdroj: https://phpsos.de/cs/blog/datenbank-auf-schadcode-pruefen/  
Stav: 25.10.2026  
Poskytovatel: PHP SOS, Nouzová pomoc pro PHP a bezpečnost serverů. Okamžitá pomoc přes WhatsApp: https://wa.me/491736494914?text=Dobr%C3%BD%20den%2C%20PHP%20SOS%2C%20pot%C5%99ebujeme%20pomoc%20s%20na%C5%A1%C3%ADm%20PHP%20serverem.%20Firma%3A%20%E2%80%A6%20Web%3A%20%E2%80%A6

**Stručně:** Chcete-li zkontrolovat databázi na škodlivý kód, prohledejte export nebo kopii čtecími dotazy na vložené skripty, cizí adresy a zakódovaný kód v obsahu a nastaveních. Zkontrolujte také triggery, plánované události, uložené procedury a databázové uživatele. Čistěte až po posouzení a nikdy slepým hledáním a nahrazením, protože se jinak rozbijí serializovaná data.

## Slepá skvrna mnoha čištění

Po průniku kontroluje většina provozovatelů soubory. Nahradí jádro CMS, smaže podezřelé soubory PHP a znovu nainstaluje rozšíření. Web pak vypadá čistě a o týden později zase přesměrovává na cizí stránky. Příčina bývá v databázi, která byla při čištění převzata beze změny.

Pro útočníky je databáze lákavým úkrytem. Skript ve widgetu se doručuje na každé stránce. Změněné nastavení adresy odkloní všechny návštěvníky. Další administrátorský účet otevírá dveře pro pozdější dobu. Nic z toho se při skenu souborů neprojeví.

Po PHP2Shell, tedy zranitelnostech CVE-2026-109618 a CVE-2026-109619 se spuštěním kódu bez přihlášení, proto databáze patří do každé kontroly. Kdo může na serveru spouštět kód, může zpravidla přečíst přístupové údaje k databázi z konfigurace a tam libovolně zapisovat. Jak aplikace s databází vůbec komunikuje, vysvětluje stránka [PHP a databáze: PDO a mysqli](https://phpsos.de/cs/php/php-und-datenbanken/).

## Kde se škodlivý kód v databázi skrývá

| Místo nálezu | Typický obsah | Účinek |
|---|---|---|
| Obsah (příspěvky, stránky, produkty) | bloky `<script>`, neviditelné odkazy, `<iframe>` | škodlivý kód nebo spam pro návštěvníky |
| Nastavení a volby | změněná adresa webu, cizí skripty ve widgetech nebo volbách motivu | přesměrování, skripty na všech stránkách |
| Tabulky uživatelů | další administrátoři | trvalý přístup |
| Triggery | kód, který při každém uložení mění obsah | škodlivý kód se po vyčištění vrací |
| Plánované události | opakující se úlohy na databázovém serveru | změny bez přístupu přes web |
| Databázoví uživatelé | další účty s rozsáhlými právy | přístup mimo CMS |

Poslední tři řádky se přehlížejí zvlášť často, protože nejsou v tabulkách CMS, ale v samotném databázovém serveru.

U e-shopů zaslouží zvláštní pozornost jedno místo nálezu: nastavení, kterými se do pokladny a dokončení objednávky vkládají další skripty. Cizí skript na tomto místě může číst zadání zákazníků dříve, než se šifrovaně odešlou poskytovateli plateb. Zkontrolujte proto cíleně všechna pole pro kód v hlavičce a patičce, vložení sledovacích kódů a nastavení vzhledu, která působí na stránkách pokladny.

Myslete také na další databáze na stejném serveru. Testovací a stagingové kopie, staré stavy projektů nebo databáze jiných webů často leží vedle a jsou dosažitelné se stejnými přístupovými údaji. Co se najde v produkční databázi, je třeba zkontrolovat i tam, než se kopie později znovu použije jako základ.

## Kontrola databáze na škodlivý kód: obsah a nastavení

Pracujte na exportu. Je zároveň zajištěním důkazů i podkladem pro hledání. Export lze prohledávat jako textový soubor, aniž by se zatěžovala běžící databáze:

```bash
# Vytvořit konzistentní export (přístupové údaje se vyžádají)
mysqldump --single-transaction --routines --triggers --events -u BENUTZER -p DATENBANK > export.sql
sha256sum export.sql > export.sql.sha256

# Spočítat typické vzorce v exportu
grep -oiE '<script[^>]{0,80}' export.sql | sort | uniq -c | sort -rn | head -30
grep -oiE '(eval\(|base64_decode|fromCharCode|document\.write|atob\()' export.sql | sort | uniq -c
grep -oiE 'https?://[a-z0-9.-]+' export.sql | sort | uniq -c | sort -rn | head -50
```

Poslední dotaz vypíše všechny domény, které se v databázi vyskytují, seřazené podle četnosti. Cizí domény, které nikdo z týmu nezná, jsou nejdůležitějšími kandidáty. Pro cílené dotazy přímo v databázi se hodí příkazy SELECT. Příklad používá tabulky WordPressu; předponu a názvy tabulek jiných systémů najdete v jejich dokumentaci:

```sql
-- Nastavení se skripty nebo podezřelými funkcemi
SELECT option_name, LENGTH(option_value) AS laenge
FROM wp_options
WHERE option_value LIKE '%<script%'
   OR option_value LIKE '%eval(%'
   OR option_value LIKE '%base64_decode%'
ORDER BY laenge DESC;
```

Záznamy s velmi velkým obsahem zaslouží zvláštní pozornost. Pozadí k úkrytům specifickým pro WordPress nabízí průvodce [Hledání zadních vrátek ve WordPressu](https://phpsos.de/cs/ratgeber/backdoor-wordpress-finden/).

## Triggery, události a databázové účty

Triggery a plánované události mnoho webových aplikací vůbec nepředpokládá. Pokud existují, měl by někdo umět vysvětlit proč. Tyto dotazy čtou jen ze systémových tabulek MySQL a MariaDB:

```sql
-- Triggery ve všech databázích
SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_OBJECT_TABLE, CREATED
FROM information_schema.TRIGGERS;

-- Plánované události
SELECT EVENT_SCHEMA, EVENT_NAME, STATUS, CREATED, LAST_EXECUTED
FROM information_schema.EVENTS;

-- Uložené procedury a funkce
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, CREATED
FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema');

-- Databázoví uživatelé
SELECT user, host FROM mysql.user ORDER BY user;
```

Pokud vaše aplikace používá PostgreSQL nebo jiný databázový systém, systémové tabulky a příkazy se jmenují jinak; princip zůstává stejný. Pro analýzu doporučujeme samostatného databázového uživatele, který smí jen číst. Tak ani překlep v dotazu nic nezmění a kontrola nezanechá v datech žádné stopy.

Trigger, který při ukládání příspěvku připojí kód, vysvětluje, proč se škodlivý kód po každém vyčištění vrací. Neznámí databázoví uživatelé patří ke kontrole účtů stejně jako administrátorské účty v CMS; více v článku [Hledání cizích administrátorských účtů v CMS a na serveru](https://phpsos.de/cs/blog/fremde-admin-konten-finden/).

## Vyčistit čistě, aniž by se zničila data

Čištění je nejcitlivější část. Tento postup se osvědčil:

1. **Posoudit nálezy:** Každý nález se zařadí jako známý, nevinně vysvětlitelný, nebo cizí. Sledovací a mapové kódy bývají legitimní.
2. **Uzavřít vstupní bránu:** Dostat PHP na opravený stav (8.5.12, 8.4.27, 8.3.36, 8.2.35 nebo potvrzený backport), restartovat všechny workery, aktualizovat aplikaci.
3. **Odstranit cíleně:** Cizí obsah čistit přes aplikaci nebo nástroji, které se serializovanými daty zacházejí správně. Cizí triggery, události a účty smazat.
4. **Změnit přístupové údaje:** Nové heslo k databázi zapsat do konfigurace aplikace, práva uživatele aplikace omezit na vlastní databázi.
5. **Zkontrolovat znovu:** Vyhledávací dotazy po několika dnech zopakovat.

> **Důležité:**
> Nic nenahrazujte funkcí hledat a nahradit v exportu SQL. Serializovaná data PHP ukládají délku každého řetězce. Když se délka změní, nastavení se stane nečitelným a web může vypadnout.

Přesměrování, která se objevují i při čisté databázi, mají příčinu v jiné vrstvě. S vymezením pomůže článek [Web přesměrovává na cizí stránky](https://phpsos.de/cs/blog/website-leitet-um/).

## Jak konkrétně pomáhá PHP SOS?

- Databázi zajistíme s kontrolním součtem a export prohledáme na skripty, cizí domény a zakódovaný kód.
- Zkontrolujeme triggery, události, procedury a databázové uživatele, kteří leží mimo CMS.
- Nálezy vyčistíme v rámci [odstranění malwaru](https://phpsos.de/cs/leistungen/malware-entfernung/), aniž bychom poškodili serializovaná data.
- Omezíme práva uživatele aplikace a po vyčištění kontrolu zopakujeme.


## Časté dotazy

**Může být škodlivý kód ukryt v databázi?**  
Ano. Útočníci zapisují JavaScript do příspěvků, popisů produktů nebo widgetů, mění nastavení adres kvůli přesměrování nebo zakládají administrátorské účty. V MySQL a MariaDB mohou data navíc měnit triggery a plánované události. Sken souborů nic z toho nenajde.

**Jak databázi prohledat, aniž bych něco rozbil?**  
Pracujte na exportu nebo kopii a používejte jen dotazy SELECT. Export lze navíc jako textový soubor prohledávat pomocí grep. Změny provádějte teprve tehdy, když je každý nález posouzen a existuje záloha.

**Proč bych nálezy neměl čistit funkcí hledat a nahradit v exportu?**  
Mnoho CMS ukládá nastavení jako serializovaná data PHP, u kterých se spolu s každým řetězcem ukládá i jeho délka. Nahrazení změní délku, ale ne údaj o ní, a nastavení se stane nečitelným. Čistěte přes aplikaci nebo nástroji, které serializovaným datům rozumějí.

**Je každý skript v databázi podezřelý?**  
Ne. Sledovací kódy, mapy, videa nebo chatovací widgety se ukládají rovněž jako skript. Rozhodující je, zda záznam a cílovou adresu někdo z týmu zná.

## Zdroje

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
- [php.net: bezpečnostní oznámení](https://www.php.net/)
