Logování a audit
Co se loguje kam (chyby PHP, logy webového serveru, audit API a záznam změn), co ne, dotazy kdo-co-kdy, uchování a audit:prune, tabulky záznamu změn a poznámky k soukromí.
Tato stránka vysvětluje, co web na WBengine zaznamenává, kam, jak dlouho a jak se zeptat „kdo, co a kdy změnil“.
Co se loguje kam
| Zdroj | Kam | Co |
|---|---|---|
| Chyby PHP a frameworku | PHP error_log |
Varování, výjimky, „cache disabled: ...“ a řádek s krátkým referenčním kódem u každé chyby 5xx v API v2. |
| Webový server | přístupové a chybové logy Nginxu nebo Apache | Každý požadavek HTTP: čas, adresa, URL, stav. Jediné místo s IP adresami. |
| Požadavky API v2 | tabulka cms_api_audit |
Jeden řádek za každé ověřené volání: kdo, jaká operace, výsledek. |
| Změny obsahu a struktury | tabulka cms_api_changes |
Jeden řádek za každý zápis s aktérem, zdrojem, akcí a daty před a po. |
| Koncepty článků | tabulka cms_api_revisions |
Historie konceptů článku pro náhled a obnovu. |
Chybový log PHP a referenční kódy
PHP zapisuje přes error_log: do souboru z ini hodnoty error_log, jinak do chybového logu webového serveru (log PHP-FPM, ErrorLog Apache, chybový log Nginxu u chyb FastCGI). V produkci ponechte display_errors = Off a log_errors = On. Když volání API v2 skončí chybou serveru (5xx), klient dostane obecnou zprávu s krátkým referenčním kódem, například ref:7f3a9c. Stejný kód se zapíše i s podrobnostmi do error_log a do auditního řádku, takže v logu hledáte přesně tento kód.
Logy webového serveru a kontejnery
Nginx a Apache mají přístupové a chybové logy, obvykle v /var/log/nginx/ a /var/log/apache2/. V dockerových image posílá Apache oba logy i chyby PHP na výstup kontejneru, čtou se příkazem docker compose logs web (nebo docker logs <kontejner>). Výchozí ovladač json-file roste bez omezení: nastavte max-size a max-file v sekci logging souboru Compose nebo v /etc/docker/daemon.json, případně výstup posílejte do sběrače logů. Hostitelský Nginx před kontejnery má navíc vlastní logy.
Auditní tabulka cms_api_audit
Sloupce: audit_id, integration_id (klíč), central_actor (označení redaktora od centrálního Adminu, nedůvěryhodný volný text do 128 znaků), local_user_id (místní správce při správě klíčů), action, outcome, detail a created_at (čas Unix).
outcome |
Význam |
|---|---|
allowed |
Klíč byl platný a měl scope. Patří sem i čtení, takže čtení obsahu zanechá stopu (kdo, jaká operace, kdy), nikdy však vrácená data. |
unauthorized |
Klíč chyběl, byl neplatný nebo odvolaný (HTTP 401). integration_id je prázdné. |
forbidden |
Klíč je platný, ale nemá požadovaný scope (HTTP 403). |
rejected |
Ověřený zápis byl odmítnut: validace, nenalezeno, konflikt, neúspěšná podmínka If-Match (412 nebo 428). detail obsahuje kód chyby. |
error |
Chyba serveru (5xx). detail je ref:<reference>, tentýž kód jako v error_log. |
Záznam změn cms_api_changes
Každá cesta zápisu vytvoří jeden řádek: change_id, resource (pages, menu, sections, boxes a articles u obsahu, user, cache a audit u ostatních operací), resource_id, action, before_data a after_data (snímky JSON), integration_id, central_actor, source, local_user_id a created_at.
source |
Kdo zapsal | Aktér |
|---|---|---|
v2 |
API v2 (centrální Admin), ve stejné transakci jako změna obsahu | integration_id a central_actor |
v1 |
Starší záznamy zapsané již zrušeným rozhraním (nové nevznikají) | local_user_id, integration_id je 0 |
cli |
bin/wbe user:create, user:password, user:delete a audit:prune |
central_actor je cli:<uživatel operačního systému>, integration_id je 0 |
Obsahové zdroje mají množná čísla (pages, menu, sections, boxes, articles); uživatelé, vyprázdnění cache a mazání záznamů používají jednotná čísla user, cache a audit, takže se nikdy neobjeví v historii /changes obsahového zdroje. Koncepty článků a obnovené verze jsou v cms_api_revisions: revision_id, article_id, payload, action, integration_id, central_actor, created_at. Revize, na kterou koncept stále odkazuje, se nikdy nesmaže.
Co se neloguje
- Těla požadavků a odpovědí. Audit drží operaci a výsledek, záznam změn výsledná data.
- IP adresy. Existují jen v přístupovém logu webového serveru.
- Klíče API, tokeny a hesla. Změna hesla se zapíše jako
passwordChanged: truea nic víc. - Zobrazení veřejných stránek. Vlastní analytika (viz přehled nastavení) drží jen anonymní denní součty.
Redakce
Řádky zapsané přes cli (a starší řádky v1) se redigují: každý klíč nazvaný password, token, secret, key nebo hash (také apiKey, key_hash) se uloží jako [redacted]. Řádky v2 ukládají data tak, jak přišla, protože je přehrává obnova struktury, proto nedávejte tajné hodnoty do obsahu stránek, menu ani článků.
Kdo, co, kdy
Všechny hodnoty created_at jsou časy Unix. Příklady:
-- posledních 20 změn s tím, kdo a kdy
SELECT FROM_UNIXTIME(created_at) AS at, source, resource, resource_id, action,
COALESCE(central_actor, local_user_id) AS actor, integration_id
FROM cms_api_changes ORDER BY change_id DESC LIMIT 20;
-- historie jednoho článku i s daty
SELECT FROM_UNIXTIME(created_at) AS at, action, central_actor, before_data, after_data
FROM cms_api_changes WHERE resource = 'articles' AND resource_id = '12' ORDER BY change_id;
-- vše, co jeden redaktor udělal za posledních 7 dní
SELECT FROM_UNIXTIME(created_at) AS at, resource, resource_id, action
FROM cms_api_changes WHERE central_actor = 'anna@example.com' AND created_at > UNIX_TIMESTAMP() - 7 * 86400;
-- odmítnutá a selhaná volání dnes a neúspěšné ověření
SELECT FROM_UNIXTIME(created_at) AS at, integration_id, central_actor, action, outcome, detail
FROM cms_api_audit WHERE outcome <> 'allowed' AND created_at > UNIX_TIMESTAMP(CURDATE()) ORDER BY audit_id DESC;
-- jak často se které klíče používají
SELECT integration_id, outcome, COUNT(*) FROM cms_api_audit GROUP BY integration_id, outcome;
Z příkazové řádky vypíše audit:list poslední změny bez dat před a po:
php vendor/bin/wbengine.php audit:list --limit=50 --resource=articles --actor=anna@example.com --config=src/Config/Settings.json --root=src
--limit je 1 až 500 (výchozí 20), --actor odpovídá označení aktéra přesně, nebo místnímu ID uživatele, je-li číselné. Centrální Admin čte tatáž data přes HTTP, viz další část.
Přehled změn přes HTTP
GET /api/v2/changes vrací záznam změn od nejnovějších, bez dat před a po. Vyžaduje HTTPS a integrační klíč s oprávněním audit:read. Centrální Admin přehled zobrazuje na stránce Aktivita webu, a to jen správcům webu. Klíč bez tohoto oprávnění je třeba nahradit novým klíčem.
Parametry dotazu: page a per_page (1 až 100, výchozí 25); filtry s přesnou shodou resource, resource_id, action, source (v2, v1 nebo cli) a actor; since a until jako epoch sekundy. Neplatný filtr vrací 400. S outcome=rejected přehled místo toho vypíše odmítnuté a neúspěšné zápisy z cms_api_audit s kódem chyby v detail.
Každý záznam má change_id, created_at, resource, resource_id, action, source, actor, integration_id a local_user_id. Samotné čtení přehledu se zapisuje do auditní tabulky jako changes.list.
Uchování a mazání
Nic se nemaže automaticky. Klíče v Settings.json (oba mají výchozí hodnotu 365, povoleno 30 až 3650, neplatná hodnota vyvolá chybu):
"audit": { "retentionDays": 365, "revisionRetentionDays": 365 }
audit.retentionDays platí pro cms_api_audit a cms_api_changes, audit.revisionRetentionDays pro cms_api_revisions. Mazání spouštějte z cronu:
27 3 * * * www-data /usr/bin/php /var/www/wbengine-skeleton-app/vendor/bin/wbengine.php audit:prune --config=/var/www/wbengine-skeleton-app/src/Config/Settings.json --root=/var/www/wbengine-skeleton-app/src >> /var/log/wbengine-cron.log 2>&1
audit:prune --dry-run jen spočítá, --days=N přepíše oba klíče pro jedno spuštění. Nejnovější změna každého zdroje zůstává, ať je jakkoli stará (její id je součástí ETagu struktury a obnovy), stejně jako každá revize, na kterou odkazuje koncept. Každé skutečné spuštění se zapíše jako změna cli zdroje audit. V Dockeru spusťte příkaz z cronu na hostiteli jako docker compose -f docker-compose.production.yml exec -T web php vendor/bin/wbengine.php audit:prune ....
Příprava tabulek záznamu změn
Weby, které používají API v2, potřebují sloupce záznamu změn source, local_user_id a detail a indexy created_at. Jednou po záloze spusťte sh bin/update-database.sh DATABASE; lze ho bezpečně spustit znovu. vendor/bin/wbengine.php doctor hlásí neúspěšnou kontrolu, dokud sloupce neexistují; do té doby se přeskakují a nic jiného se nemění.
sh bin/update-database.sh wbengine_skeleton_app
docker compose -f docker-compose.production.yml exec -T web sh bin/update-database.sh --print \
| docker compose -f docker-compose.production.yml exec -T db sh -c 'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysql -uroot wbengine_skeleton_app'
První příkaz je pro databázi na hostiteli, druhý pro produkční Compose.
Poznámky k soukromí
- Označení aktérů, řádky uživatelů a snímky obsahu mohou obsahovat osobní údaje, například e-mailové adresy a jména. Auditní tabulky berte jako osobní údaje: omezte přístup k databázi a zahrňte je do záznamů o zpracování.
- Zvolte uchování podle svých zásad a pamatujte, že zálohy databáze drží řádky déle, než říká nastavení.
- IP adresa žije jen v logách webového serveru. Jejich rotaci a uchování nastavte zvlášť (
logrotate, volby logů Dockeru). - Audit je stopa toho, kdo co udělal, nikoli toho, co návštěvníci četli: zobrazení veřejných stránek se po návštěvnících nezaznamenávají.