Nightward
Документація · версія 1.0.2

Як працює Nightward

Nightward - монітор безпеки WordPress, що працює під час роботи сайту. Він записує, що роблять встановлені плагіни й теми, називає файл і рядок, які за це відповідають, і звітує на пошту. Тут пояснено кожен монітор, що означає кожна знахідка і що з нею робити.

Встановлення

Вимоги

  • WordPress 6.2 або новіший, PHP 7.4 або новіший. Підтримуються MySQL, MariaDB і інтеграція з базою SQLite.
  • Робочий wp_mail(). На більшості хостингів це означає SMTP-плагін.
  • WP-Cron, що запускається хоча б щогодини. Рекомендовано справжнє серверне cron-завдання, див. Планові завдання.
  • Бажано, щоб тека wp-content/mu-plugins була доступна для запису: тоді Nightward стартує раніше за інші плагіни.

Встановлення

  1. Завантажте nightward-1.0.2.zip.
  2. У WordPress відкрийте Плагіни → Додати → Завантажити плагін, оберіть zip і натисніть Встановити.
  3. Натисніть Активувати. В меню адмінки з'явиться пункт Nightward.
  4. Відкрийте Nightward → Налаштування, перевірте час звіту й отримувачів і натисніть Надіслати тестовий звіт.

Що відбувається під час активації

  • Створюються три таблиці: події, вихідні хости й хеші файлів.
  • Записується ранній завантажувач wp-content/mu-plugins/0-nightward-early.php. Must-use плагіни завантажуються раніше за звичайні, тож Nightward бачить їхні хуки й запити з першого рядка. Файл видаляється при деактивації Nightward.
  • Плануються щоденний звіт, щогодинна перевірка й нічне обслуговування.
  • Через хвилину стартує перше сканування цілісності. Воно фіксує поточний стан кожного пакета.
  • Починається період навчання. Див. Перша доба.

Оновлення

Nightward розповсюджується з цього сайту, а не з WordPress.org. Щоб оновити, деактивуйте плагін, замініть теку nightward новою версією і активуйте знову. Події, еталони й налаштування зберігаються. Заміна файлів самого Nightward змінює його власний знімок, тому після оновлення запустіть Цілісність → Сканувати зараз і прийміть пакет Nightward, якщо він з'явиться в списку.

Вихідний код і вся історія змін - на GitHub. Там само можна повідомити про помилку через Issues.

Перша доба

Монітор, який повідомляє про звичайну поведінку кожного плагіна як про новину, марний. Перші 24 години (період навчання, змінюється в налаштуваннях) Nightward записує норму сайту, не повідомляючи про неї:

  • з якими хостами зв'язується кожен плагін;
  • які сторонні callback підключені до чутливих хуків;
  • які є заплановані завдання;
  • які файли є в кожному пакеті.

Критичні знахідки надходять з першої хвилини: код з eval() на хуку, адміністратор, створений анонімним запитом, запит до сервісу вставок. Екран «Огляд» показує, скільки лишилося до кінця навчання.

Встановлюйте на сайт, який вважаєте чистимУсе, що вже є на сайті під час навчання, стає частиною еталона. Якщо ставите Nightward на сайт, який підозрюєте у зламі, після першої доби самостійно перегляньте екрани «Хуки й Cron» і «Мережа».

Повторне навчання після оновлень

Коли плагін чи тему встановлюють, активують або оновлюють через WordPress, вони отримують шість годин, протягом яких нові хуки записуються як новий еталон. Вони все одно з'являються в журналі (як Низький для хуків входу й видимості, Інфо для решти), тож новий плагін, що підключився до входу, буде видно в наступному звіті.

Події та рівні серйозності

Усі монітори пишуть в один журнал подій. У події є рівень, розділ, назва, пояснення і, де можливо, плагін чи тема, файл і рядок, які за неї відповідають.

Рівні

РівеньЗначенняМиттєвий лист
КритичнийОзнаки зламу або зміна, що дає комусь контроль: прихований адміністратор, код з eval() на хуку входу, перехоплене оновлення, шкідливий код в uploads.Так
ВисокийЙмовірна проблема, але є легітимні пояснення: перевірка ліцензії з локальною відповіддю, файл змінився без зміни версії, відкритий debug-лог.За бажанням
СереднійВарто перевірити: пакети оновлень по HTTP, дозволене виконання PHP в uploads, сайт без HTTPS.Ні
НизькийЗміни, про які варто знати: плагін звернувся до нового хоста, вхід з нової мережі, оновлення поза WordPress.Ні
ІнфоЗаписи для контексту: адміністратор, створений на екрані «Користувачі», новий еталон після оновлення.Ні

Статуси

СтатусЩо означає
ВідкритаНова або повторилася після вирішення. Рахується на огляді і в лічильнику меню (лише критичні й високі).
ПереглянутаВи її бачили і працюєте над нею. Лишається в списку, але не вважається новою.
ВирішенаВиправлено. Якщо те саме станеться знову, подія відкриється і зможе знову надіслати сповіщення.
ІгноруєтьсяДля цього сайту це очікувано. Про таку саму подію більше не повідомлятиметься.

Дублікати

Одна й та сама знахідка зберігається один раз із лічильником. Плагін, що зробив той самий запит 500 разів, - це одна подія з × 500, і сповіщення по ній одне. Для файлових знахідок хеш файлу входить в ідентифікацію: якщо проігнорований файл знову зміниться, з'явиться нова подія.

Атрибуція

Знахідки називають відповідальний компонент: плагін чи тему за назвою, must-use плагін, drop-in на кшталт db.php, ядро WordPress або код, виконаний через eval(), якщо в коду немає файлу. Для подій під час роботи Nightward проходить стек викликів до першого кадру, що належить плагіну чи темі. Для callback хуків використовується reflection PHP, щоб знайти файл і рядок, де визначено функцію.

Події зберігаються незалежно від мови і показуються мовою того, хто їх читає, - в адмінці й у листах.

Вихідні запити

Кожен виклик через HTTP API WordPress (wp_remote_get(), wp_remote_post() і все, що на них побудовано) записується з хостом, плагіном, що його зробив, файлом і рядком виклику. Значення параметрів запиту видаляються перед збереженням, тож ліцензійні ключі й токени з URL не зберігаються.

Знахідки

ЗнахідкаРівень
Запит до сервісу вставок або анонімного обміну файлами (pastebin.com, paste.ee, transfer.sh, file.io…)Критичний
Запит до тунелю (ngrok, швидкі тунелі Cloudflare, localtunnel…), сервісу перехоплення запитів (webhook.site, requestbin, pipedream), домену динамічного DNS, адреси .onionКритичний
Запит до polyfill.io і пов'язаних доменів з атаки на ланцюг постачання 2024 рокуКритичний
Запит до відомого розповсюджувача піратських плагінівКритичний
Запит на публічну IP-адресу замість доменуВисокий
Запит до Telegram Bot API або вебхука DiscordСередній
Плагін уперше звернувся до хоста (після періоду навчання)Низький або Інфо для відомих сервісів

Власні домени плагіна не вважаються новими хостами. Nightward бере їх із заголовків Plugin URI, Author URI і Update URI, ігноруючи платформи на кшталт GitHub, WordPress.org і CodeCanyon.

Довірені хости

Якщо знахідка очікувана, наприклад ваш власний плагін пересилає пошту в Telegram-бот, натисніть Довіряти в події або на екрані «Мережа», або додайте домен у Налаштування → Довірені хости. Запити й завантаження оновлень з довірених хостів у звіт не потрапляють.

Перехоплення HTTP

WordPress дозволяє будь-якому плагіну самому відповісти на HTTP-запит через фільтр pre_http_request. Тоді запит не виходить за межі сервера. Плагіни кешування й інструменти «вимкнути зовнішні запити» роблять це легітимно. Піратські плагіни так відповідають на власні перевірки ліцензії, а шкідливий код - ховає або підробляє інформацію про оновлення.

Nightward ставить мітку після кожного callback на pre_http_request. Коли з'являється відповідь, він точно знає, який callback її створив, навіть якщо кілька анонімних функцій мають однаковий пріоритет. Подія показує callback, файл і рядок, підроблений код статусу й початок підробленої відповіді.

ЗнахідкаРівень
Запит заблоковано через WP_ErrorНизький
Відповідь підмінено для звичайного запитуСередній
Перевірка ліцензії, активації, верифікації чи оновлення отримала відповідь 200 локальноВисокий
API WordPress.org відповіло локальноВисокий
Один callback підробив відповіді для трьох і більше доменівКритичний
Callback-перехоплювач створено через eval()Критичний
Подія перехоплення з callback, розташуванням і підробленою відповіддю

Чутливі хуки

Деякі хуки WordPress вирішують, хто увійшов, що дозволено користувачу, що бачить адміністратор і куди йдуть оновлення та пошта. Nightward запам'ятовує кожен сторонній callback на цих хуках і повідомляє про нові.

ГрупаХуки
Автентифікація та праваauthenticate, wp_authenticate_user, determine_current_user, check_password, user_has_cap, map_meta_cap, rest_authentication_errors, application_password_is_api_request, auth_cookie_valid, wp_login
Що бачить адміністраторall_plugins, pre_user_query, users_list_table_query_args, views_users, show_advanced_plugins, site_transient_update_plugins, site_transient_update_core
Оновлення, HTTP і поштаupgrader_pre_download, upgrader_package_options, pre_set_site_transient_update_plugins, pre_set_site_transient_update_themes, http_request_args, pre_wp_mail, phpmailer_init, xmlrpc_methods
ЗнахідкаРівень
Callback на будь-якому хуку скомпільовано з рядка через eval() або create_function()Критичний
Новий callback на хуку автентифікації чи видимості від плагіна, який нещодавно не встановлювали й не оновлювалиВисокий
Новий callback з must-use плагіна, drop-in файлу чи невідомого розташуванняВисокий
Новий callback на хуку оновлень, HTTP чи поштиСередній
Новий callback одразу після встановлення чи оновлення плагінаНизький / Інфо

Callback, створені через eval(), не мають файлу-джерела, тож файлові сканери їх не знаходять. Nightward показує файл і рядок, де було викликано eval(). Екран «Хуки й Cron» показує всі поточні сторонні callback на цих хуках. Сама присутність плагіна в списку - не проблема: плагіни безпеки, членства й SMTP мусять підключатися. Але кожен рядок ви маєте впізнавати.

Користувачі та права

Прихований адміністратор - найпоширеніший спосіб зберегти доступ до зламаного сайту. Nightward стежить за кожним шляхом до прав адміністратора.

ЗнахідкаРівень
Адміністратора створено чи підвищено під час анонімного запиту, користувачем без права призначати ролі або кодом з eval()Критичний
Адміністратор з'явився в базі без виклику будь-якої функції користувачів WordPress (прямий SQL), знайдено щогодинним аудитомКритичний
Прихований адміністратор: є в базі, але немає у відфільтрованому списку користувачівКритичний
Адміністратора створив плагін, поки адміністратор працював в адмінці (наприклад, редактор ролей)Високий
Для адміністратора створено пароль застосункуСередній, Високий, якщо не з екрана профілю
Пароль чи e-mail адміністратора змінено кодом плагінаСередній, Критичний, якщо поточний користувач не має права редагувати користувачів
Адміністратора створено з WP-CLIСередній
Адміністратор увійшов з мережі (/24 для IPv4, /48 для IPv6), якої раніше не було для цього акаунтаНизький
Адміністратора створив адміністратор на екрані «Користувачі» або через REST APIІнфо

Паролі застосунків дають постійний доступ до REST і XML-RPC. Вони оминають двофакторний вхід і переживають зміну пароля, тож це тихий спосіб зберегти доступ. Якщо ви його не створювали, видаліть у профілі користувача.

Опції

Кілька налаштувань передають контроль над сайтом тому, хто їх змінить. Nightward записує, хто їх змінив і чи це сталося через екрани налаштувань.

ЗнахідкаРівень
default_role змінено на адміністратора, редактора чи менеджера магазинуКритичний
Реєстрацію відкрито при привілейованій ролі за замовчуваннямКритичний
Адресу сайту (siteurl, home) змінено поза екраном налаштуваньКритичний
Передплатник, покупець, учасник, автор або роль за замовчуванням отримали права адміністратораКритичний
E-mail адміністратора змінено поза екраном налаштуваньВисокий
Плагін активовано кодом, а не з екрана «Плагіни» чи WP-CLIВисокий
Активну тему змінено кодомВисокий
Плагін записує ту саму опцію на 60% і більше переглядів сторінокНизький
Autoload-опції важать понад 800 КБ (понад 3 МБ - середній)Низький / Середній

Записи опцій перевіряються вибірково приблизно на одному перегляді з двадцяти на фронтенді й оцінюються щогодини після щонайменше 15 вибірок. Плагін, що пише в базу майже на кожному відвідуванні, марнує ресурси й ламає повносторінковий кеш. У ліцензійному коді це також може означати, що сайт «дзвонить додому» на кожному запиті.

Заплановані завдання

Шкідливий код часто повертається після чистки, бо заплановане завдання завантажує його знову. Щогодинна перевірка порівнює WP-Cron з відомим списком.

ЗнахідкаРівень
Аргументи завдання містять PHP-код, довгий base64-блок або URL на файлКритичний
Ім'я завдання схоже на випадкове (hex-рядки, довгі імена без голосних і розділювачів)Високий
Нове завдання, до якого в цьому запиті не підключено обробникНизький
Нове завдання (після періоду навчання)Інфо

Екран «Хуки й Cron» показує кожне завдання з розкладом, наступним запуском і плагіном, чия функція його виконує. Завдання без обробника зазвичай лишаються від видалених плагінів.

Цілісність файлів

Кожен файл коду (PHP, JavaScript, .htaccess, .user.ini, JSON, Twig) в ядрі, плагінах і темах порівнюється з еталоном.

ПакетЕталон
Ядро WordPressОфіційні контрольні суми з api.wordpress.org для вашої версії й локалі.
Плагіни з WordPress.orgОфіційні контрольні суми версії з downloads.wordpress.org.
Преміум-плагіни й усі темиВласний знімок Nightward, зроблений під час першого сканування кожної версії («Власний знімок»).
ЗнахідкаРівень
Змінений чи неочікуваний PHP-файл з ознаками шкідливого коду: eval(base64_decode(, дані запиту в eval/system, preg_replace /e, віддалений include, довгі base64-блоки, ланцюжки chr(), PHP у заголовку зображенняКритичний
Файл ядра відрізняється від релізу або невідомий файл серед файлів ядраВисокий
Файл плагіна з WordPress.org відрізняється від офіційної копії цієї версії або невідомий PHP-файл у ньомуВисокий
Файл преміум-плагіна чи теми змінився або додано новий PHP-файл, а номер версії лишився тим самимВисокий
Версію пакета змінено поза оновлювачем WordPress (FTP, SSH, деплой)Низький
Файли видалено без зміни версіїНизький

Як іде сканування

Сканування запускається щоночі (о 03:30 за замовчуванням) і після кожного оновлення, порціями по 400 файлів через WP-Cron, тож воно завершується навіть на шаред-хостингу. Цілісність → Сканувати зараз запускає його з браузера з індикатором прогресу. Коли відновлений файл знову збігається з еталоном, його подія закривається автоматично.

Прийняття власних змін

Якщо ви самі змінили преміум-плагін чи тему, перегляньте знахідку й натисніть Прийняти поточні файли для цього пакета. Поточні файли стануть новим еталоном, а відкриті події цілісності по ньому закриються.

Преміум-плагін з тим самим slug, що й безкоштовнийЯкщо файли пакета збігаються менш ніж з половиною контрольних сум WordPress.org для його slug і версії, Nightward вважає його іншим продуктом і використовує власний знімок.

Виконувані файли

Перевіряються щогодини (швидкий прохід) і щоночі (повний прохід).

ДеЩо потрапляє у звітРівень
uploadsPHP та інші виконувані скрипти; .user.ini / php.ini; .htaccess, що вмикає обробники скриптів чи налаштування PHP; медіафайли з PHP-кодомВисокий, Критичний з ознаками шкідливого коду
uploadsПодвійні розширення на кшталт photo.php.jpgСередній
Корінь wp-contentPHP-файли, що не є drop-in файлами WordPress чи відомими конфігураціями кешуВисокий
mu-pluginsНові must-use плагіни (після періоду навчання)Високий
cache, languagesВиконуваний PHP (файли перекладів .l10n.php і файли даних кешу пропускаються)Високий
upgradePHP, що лишився після перерваних оновленьСередній

Файли даних, у яких першим рядком стоїть exit чи die, нічого не можуть виконати і в звіт не потрапляють. Так зберігають дані Sucuri, Wordfence і кілька плагінів кешу. Заглушки index.php «Silence is golden» теж пропускаються. Коли файл зі звіту видаляють, його подія закривається при наступному проході.

Канал оновлень

Nightward перевіряє, звідки приходять оновлення: і ті, що чекають у Майстерня → Оновлення (щогодини), і кожен пакет, який оновлювач справді завантажує.

ЗнахідкаРівеньЗавантаження
Оновлення плагіна з WordPress.org чи ядра роздає інший серверКритичнийЗавжди блокується
Пакет з відомого шкідливого хоста (сервіси вставок, тунелі, піратські розповсюджувачі)КритичнийЗавжди блокується
Пакет з хоста, не пов'язаного з розробником, або з голої IP-адресиСереднійБлокується, якщо ввімкнено налаштування
Пакет завантажується через звичайний HTTPСереднійДозволено
Запис у списку оновлень без обов'язкового поля pluginСередній-

Хост пакета вважається нормальним, якщо це власний домен плагіна, довірений хост або поширена платформа розповсюдження (GitHub, Amazon S3 і CloudFront, Freemius, Envato, WooCommerce тощо). Знахідки щодо оновлень, які очікують, перелічують плагіни й теми, що можуть переписувати список оновлень, - тож відомо, де шукати.

«Undefined property: stdClass::$plugin» на сторінці Плагіни → ДодатиЦе попередження PHP з'являється, коли сторонній оновлювач записує власний запис у список оновлень WordPress без поля plugin. WordPress.org таких записів не створює. Починаючи з версії 1.0.2, Nightward повідомляє про це і показує код, що змінює список оновлень. Зазвичай джерело - вбудований оновлювач плагіна з неофіційного джерела.

Захищеність

Перевіряється щоночі й на вимогу з Захищеність → Запустити перевірку. Там, де це важливо, перевірка запитує файл ззовні через loopback-запит, так, як це зробив би зловмисник. Події створюються лише для проваленої перевірки. Оцінка починається зі 100 і втрачає бали за кожну провалену перевірку чи попередження залежно від рівня.

ПеревіркаКоли провалюється
Відкриті файлиdebug.log (або ваш WP_DEBUG_LOG), .env, .git/HEAD, копії wp-config.php (.bak, .old, .save, .orig, ~, .txt, .swp), дампи SQL і архіви в корені сайту, якщо їх можна завантажити
Виконання PHP в uploadsNightward записує нешкідливий тестовий файл в uploads, запитує його і видаляє. Якщо він виконався, будь-яка вразливість завантаження файлів стає виконанням коду.
Перегляд вмісту текТека uploads показує сторінку «Index of».
XML-RPCxmlrpc.php відповідає на методи входу (багато спроб пароля в одному запиті).
Перелік користувачівREST API показує відвідувачам логіни користувачів.
Логін «admin»Одного з адміністраторів звуть admin.
HTTPSАдреса сайту не HTTPS.
Заголовки безпекиНемає X-Content-Type-Options, X-Frame-Options чи CSP frame-ancestors, Referrer-Policy, а на HTTPS-сайтах - HSTS.
Права на wp-config.phpЗапис дозволено всім або читання дозволено іншим користувачам сервера.
Редактор файлівНе задано DISALLOW_FILE_EDIT.
Показ помилокПомилки PHP показуються відвідувачам.
Версії PHP і WordPressPHP старіший за 8.1 або доступне оновлення WordPress.
Неактивні плагіниДеактивовані плагіни лишаються на диску, де їхні файли можна запитати напряму.
WP-CronЩогодинне завдання Nightward не запускалося понад три години.
# wp-config.php
define( 'DISALLOW_FILE_EDIT', true );
define( 'WP_DEBUG_DISPLAY', false );

# nginx: заборонити PHP в uploads
location ~* /wp-content/uploads/.*\.php$ { deny all; }

# Apache (.htaccess у wp-content/uploads)
<FilesMatch "\.php$">
	Require all denied
</FilesMatch>

Звіти та сповіщення

Щоденний звіт

Надсилається щодня в заданий час за часовим поясом сайту (о 20:00 за замовчуванням). Розклад перераховується після кожного звіту, тож він не зсувається при переході на літній час. Звіт містить:

  • загальний стан і лічильники за рівнями за період від попереднього звіту;
  • критичні й високі знахідки з джерелом, файлом і поясненням, далі інші знахідки коротко;
  • нові вихідні адреси і плагіни, що до них зверталися;
  • стан перевірок: останнє сканування цілісності, кількість хостів і підроблених відповідей, оцінка захищеності, стан WP-Cron.

З увімкненим Надсилати звіт, навіть якщо нічого не сталося (за замовчуванням) спокійний день теж дає короткий лист «Усе чисто». Якщо він перестав приходити, зупинився сайт, WP-Cron, доставка пошти або сам Nightward.

Миттєві сповіщення

Критичні знахідки (за бажанням і високі) надсилаються в момент виявлення, з усіма деталями й посиланням на подію. За замовчуванням - не більше 5 сповіщень на годину. Усе понад ліміт збирається в один лист, що надсилається по закінченню години.

Мова

Якщо перший отримувач - користувач сайту, звіт пишеться його мовою в WordPress. Інакше - мовою сайту. Українська й англійська є в комплекті.

Перевірка та доставка

Надіслати тестовий звіт одразу надсилає поточний звіт з позначкою тесту. Попередній перегляд відкриває його в браузері. Листи надсилаються через wp_mail() як HTML з текстовою частиною, тож нормально читаються й тоді, коли міст у Telegram чи Slack перетворює їх на текст. Якщо тест не пройшов, огляд покаже помилку поштового модуля; налаштуйте SMTP-плагін.

Лист миттєвого сповіщення

Адмінка

ЕкранДля чого
ОглядСтан сайту, відкриті знахідки за рівнями, критичні й високі пункти, розклад звітів і стан пошти, картка кожного монітора і що Nightward не бачить.
ПодіїПовний журнал із фільтрами за рівнем, розділом і статусом, пошуком за назвою, файлом чи плагіном, масовою зміною статусу й розгорнутими деталями.
МережаКод, підключений до pre_http_request, і кожен хост за 30 днів з плагіном, кількістю запитів, підроблених відповідей і помилок.
Хуки й CronСторонні callback на чутливих хуках за групами і всі заплановані завдання з обробниками.
ЦілісністьОстаннє сканування, кожен пакет з тим, з чим його звіряють, і його відкритими проблемами, Сканувати зараз і Прийняти поточні файли.
ЗахищеністьПеревірки з результатами, виправленнями й оцінкою і Запустити перевірку.
НалаштуванняУсі опції, див. нижче.

У меню адмінки є лічильник відкритих критичних і високих подій. Для екранів Nightward потрібне право manage_options.

Довідник налаштувань

НалаштуванняЗа замовчуваннямПримітки
Надсилати щоденний звіт безпекиУвімкнено
Час20:00Часовий пояс сайту (Налаштування → Загальні).
ОтримувачіE-mail адміністратора сайтуСписок через кому.
Надсилати звіт, навіть якщо нічого не сталосяУвімкненоРекомендовано.
Миттєві сповіщенняУвімкнено
Сповіщати проЛише критичніАбо критичні й високі.
Максимум сповіщень на годину5Від 1 до 50. Решта об'єднується.
МоніториУсі увімкненоКожен з дев'яти перемикачів повністю вимикає монітор.
Блокувати оновлення з непов'язаних хостівВимкненоПерехоплені оновлення з WordPress.org і шкідливі хости блокуються завжди.
Запускатися раніше за інші плагіниУвімкненоЗаписує або видаляє must-use завантажувач.
Довірені хостиПорожньоОдин домен на рядок; домен другого рівня покриває свої піддомени.
Час щоденного сканування03:30Цілісність, повний прохід uploads, захищеність, перевірка autoload, очищення.
Файлів за порцію400Від 50 до 3000. Зменште на дуже повільному хостингу.
Період навчання, годин24Від 0 до 168.
Зберігати вирішені події, днів60Від 7 до 365.

Планові завдання

ЗавданняКолиЩо робить
nightward_daily_reportЧас звітуНадсилає щоденний звіт і планує наступний.
nightward_hourlyЩогодиниЗаплановані завдання, швидкий прохід uploads, оновлення, що очікують, аудит адміністраторів, оцінка записів опцій, самоперевірка розкладу звіту.
nightward_daily_maintenanceЧас щоденного скануванняСканування цілісності, повний прохід uploads, перевірки захищеності, перевірка autoload, очищення старих подій.
nightward_integrity_stepЗа потребиНаступна порція сканування цілісності.
nightward_instant_retryЗа потребиНадсилає сповіщення, відкладені через ліміт на годину.

WP-Cron запускається лише тоді, коли сайт хтось відвідує. На сайтах з малою відвідуваністю або з кешем сторінок використовуйте справжній cron:

# wp-config.php
define( 'DISABLE_WP_CRON', true );

# crontab: кожні 5 хвилин
*/5 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

# або через WP-CLI
*/5 * * * * cd /path/to/site && wp cron event run --due-now --quiet

Вирішення проблем

Листи не приходять

Натисніть Надіслати тестовий звіт. Якщо огляд показує помилку пошти, не працює wp_mail(): встановіть і налаштуйте SMTP-плагін. Якщо тест приходить, а щоденний звіт ні, не запускається WP-Cron; див. Планові завдання.

Звіт приходить із запізненням

WP-Cron чекає на відвідування. Налаштуйте справжній cron. Крім того, Nightward щогодини перевіряє, що звіт заплановано, і відновлює розклад, якщо він загубився.

Багато подій «новий хост» після встановлення плагіна

Новий плагін звертається до своїх сервісів. Довіряйте знайомим хостам одним кліком або додайте їх у «Довірені хости».

У звіт потрапила моя власна правка плагіна

Так і працює перевірка цілісності. Натисніть Прийняти поточні файли для пакета на екрані «Цілісність».

У звіт потрапив файл іншого сервісу безпеки

Деякі сервіси кладуть файли-конектори в корінь сайту, наприклад bv_connector_<hash>.php, який створюють MalCare і BlogVault. Відкрийте файл і переконайтеся, що він належить сервісу, яким ви користуєтесь. Далі видаліть його, якщо сервісу він більше не потрібен, або позначте подію як «Ігнорувати». Проігнорований файл знову потрапить у звіт, лише якщо зміниться.

Перевірки захищеності пропускаються

Сайт не може звернутися сам до себе (loopback). Часто це обмеження файрвола чи хостингу. «Здоров'я сайту» в WordPress теж потребує loopback; попросіть хостинг дозволити запити сервера до власного домену.

Цілісність показує «очікує першого сканування»

Перше сканування стартує через WP-Cron. Запустіть його кнопкою Цілісність → Сканувати зараз.

Швидкодія і приватність

Що коштує кожен перегляд сторінки

  • Трасування стеку робиться лише тоді, коли сайт робить вихідний HTTP-запит.
  • Перевірка хуків порівнює коротку сигнатуру з однієї невеликої autoload-опції. Повне порівняння запускається, лише коли набір callback змінюється.
  • Записи опцій перевіряються вибірково приблизно на одному перегляді з двадцяти на фронтенді.
  • Повний пошук callback з eval() запускається приблизно на одному запиті з сорока.
  • Події записуються одним проходом у кінці запиту. Лише критичні записуються одразу.
  • Сканування файлів, аудити й перевірки захищеності йдуть у фоні.

Приватність

У Nightward немає акаунта, телеметрії чи зовнішнього сервісу. Він звертається лише до api.wordpress.org і downloads.wordpress.org по контрольні суми та до вашого сайту для перевірок захищеності. У збережених URL значення параметрів видаляються. Звіти йдуть через wp_mail() вашого сайту. IP-адреси входів адміністраторів зберігаються як мережі (/24 або /48) в метаданих користувача, не більше 15 останніх.

Для розробників

Кожна нова або повторно відкрита подія викликає action, через який знахідки можна переслати деінде:

add_action( 'nightward_event', function ( array $event ) {
	// ключі $event: id, module, type, severity, title, details,
	// component, file, line, fingerprint
	if ( 'critical' === $event['severity'] ) {
		// надіслати в Slack, Telegram, збирач логів...
	}
} );

Ідентифікатори модулів: outbound, interception, hooks, privilege, options, cron, integrity, uploads, update_channel, hardening, system.

Loopback-запити Nightward мають заголовок X-Nightward-Probe і не враховуються в статистиці вихідних запитів.

Переклади

Текстовий домен - nightward. Шаблон - languages/nightward.pot. Переклади також можна покласти в wp-content/languages/plugins/nightward-{locale}.mo.

Збережені дані та видалення

ДеЩо
{prefix}nightward_eventsЖурнал подій.
{prefix}nightward_egressВихідні хости за плагінами з лічильниками. Зберігаються 180 днів після останнього звернення.
{prefix}nightward_filesХеші SHA-256 пакетів із власним знімком.
Опції nightward_*Налаштування, еталони, стан сканування, стан звітів.
Метадані користувача nightward_known_netsМережі, з яких входили адміністратори.
mu-plugins/0-nightward-early.phpРанній завантажувач.

Вирішені, переглянуті й проігноровані події, а також низькі й інфо видаляються після строку зберігання. Деактивація Nightward прибирає завантажувач і планові завдання, а дані лишає. Видалення з екрана «Плагіни» прибирає таблиці, опції, transient-и, метадані користувачів, завантажувач і планові завдання.

Межі

  • Запити через «сирий» cURL, сокети чи file_get_contents() оминають HTTP API WordPress і не записуються.
  • Код, що виконується раніше за Nightward, під час роботи не відстежується: wp-config.php, drop-in файли на кшталт db.php і object-cache.php, must-use плагіни, що завантажуються раніше за 0-nightward-early.php. Цілісність їхніх файлів усе одно перевіряється, де є еталон.
  • Прямі зміни в базі знаходить щогодинний аудит, без файлу, який їх зробив.
  • Преміум-плагіни й теми вважаються довіреними в стані першого сканування.
  • Nightward - не файрвол. Він не блокує відвідувачів і не шукає сигнатури шкідливого коду. Той, хто має доступ до сервера, може вимкнути будь-який плагін, тому відсутній щоденний звіт - уже тривога.
  • Зроблено і протестовано для окремих сайтів. Активація на всю мережу працює, але звіти й налаштування не розділені за сайтами.

Список змін

  • 1.0.2 ·
    • Файли даних, що починаються з exit (Sucuri, Wordfence, плагіни кешу), більше не вважаються виконуваними скриптами в uploads. Відкриті події по них закриваються автоматично.
    • Нове: записи в списку оновлень без поля plugin потрапляють у звіт разом із кодом, що може змінювати список. Саме вони дають попередження «Undefined property: stdClass::$plugin» на сторінці Плагіни → Додати.
  • 1.0.1 ·
    • Довірені хости також прибирають знахідки щодо Telegram і Discord. Кнопка «Довіряти» з'являється в таких подіях.
    • Листи лишаються читабельними, коли міст перетворює їх на текст.
  • 1.0.0 ·
    • Перший реліз: десять моніторів, щоденний звіт і миттєві сповіщення, українська й англійська.