Як знайти та видалити приховані зовнішні посилання в Joomla 5 і 6

Перевірка зовнішніх посилань у Joomla 5 і 6

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

У старих інструкціях для такої перевірки часто пропонували Xenu Link і пошук усіх входжень base64_decode. Для Joomla 5 і 6 такий підхід уже незручний і може призвести до помилок. Ні Xenu, ні інші сторонні програми тут не обов’язкові: достатньо phpMyAdmin, консолі браузера та файлового менеджера хостингу.

Що саме варто шукати

Перевірка особливо корисна в кількох ситуаціях:

  • після встановлення або оновлення шаблону, модуля, плагіна чи компонента;
  • після відновлення сайту або усунення зараження;
  • якщо в Search Console, антивірусі або вихідному коді з’явилися незнайомі домени;
  • якщо на сайті раніше використовувалися рекламні та партнерські блоки;
  • якщо потрібно провести ревізію старого контенту.

Головне завдання — зрозуміти де зберігається посилання і чи виводиться воно на сайті зараз. Один і той самий URL може міститися в матеріалі Joomla, в HTML-модулі, у файлі розширення або лише в кеші.

Пошук зовнішніх посилань у матеріалах через phpMyAdmin

Основний текст матеріалів Joomla зберігається в таблиці #__content, у полях introtext і fulltext. Тому масову перевірку можна виконати безпосередньо в базі даних.

Для початку можна вивести перший абсолютний зовнішній URL із кожного матеріалу:

SQL — пошук зовнішніх URL
SELECT
    id,
    title,
    REGEXP_SUBSTR(
        CONCAT_WS(' ', introtext, `fulltext`),
        'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://[^"''<>[:space:]]+'
    ) AS external_url
FROM PREFIX_content
WHERE CONCAT_WS(' ', introtext, `fulltext`)
      REGEXP 'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://[^"''<>[:space:]]+'
ORDER BY id;

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

SQL-запит для списку унікальних зовнішніх доменів

У двох місцях замініть example\\.com на власний домен. Крапки в імені домену потрібно екранувати як \\..

SQL — унікальні зовнішні домени
WITH RECURSIVE
src AS (
    SELECT
        id,
        title,
        CONCAT_WS(' ', introtext, `fulltext`) AS rest
    FROM PREFIX_content
    WHERE CONCAT_WS(' ', introtext, `fulltext`)
        REGEXP 'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
),
links (id, title, url, rest, n) AS (
    SELECT
        id,
        title,
        REGEXP_SUBSTR(
            rest,
            'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
        ),
        SUBSTRING(
            rest,
            REGEXP_INSTR(
                rest,
                'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
            ) + CHAR_LENGTH(
                REGEXP_SUBSTR(
                    rest,
                    'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
                )
            )
        ),
        1
    FROM src

    UNION ALL

    SELECT
        id,
        title,
        REGEXP_SUBSTR(
            rest,
            'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
        ),
        SUBSTRING(
            rest,
            REGEXP_INSTR(
                rest,
                'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
            ) + CHAR_LENGTH(
                REGEXP_SUBSTR(
                    rest,
                    'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
                )
            )
        ),
        n + 1
    FROM links
    WHERE n < 100
      AND rest REGEXP
        'href[[:space:]]*=[[:space:]]*["'']\\Khttps?://(?!(?:[a-z0-9-]+\\.)*example\\.com(?:[/:?#]|$))[^"''<>[:space:]]+'
)
SELECT
    LOWER(REGEXP_SUBSTR(url, 'https?://\\K[^/:?#]+')) AS domain,
    COUNT(*) AS links_count,
    COUNT(DISTINCT id) AS articles_count
FROM links
WHERE url <> ''
GROUP BY domain
ORDER BY articles_count DESC, links_count DESC, domain;

Список зовнішніх доменів і кількість посилань у матеріалах Joomla

На реальному сайті такий запит може повернути десятки або сотні доменів. Це не означає, що всі вони шкідливі. Спочатку дивіться на контекст: офіційні сайти Joomla, Google, сервіси, про які йдеться в статті, та старі партнерські майданчики можуть бути цілком пояснюваними. Підозру викликають насамперед невідомі домени, які повторюються в не пов’язаних між собою матеріалах або які ви точно не додавали.

Перевіряємо HTML-модулі Joomla

Зовнішнє посилання може міститися не в матеріалі, а в користувацькому HTML-модулі. Для таблиці модулів корисно одночасно вивести URL і стан публікації.

SQL — перевірка модулів
SELECT
    id,
    title,
    position,
    published,
    REGEXP_SUBSTR(
        content,
        'https?://[^"''<>[:space:]]+'
    ) AS external_url
FROM PREFIX_modules
WHERE content REGEXP 'https?://'
  AND content NOT REGEXP 'https?://([a-z0-9-]+\\.)*example\\.com'
ORDER BY id;

Перевірка зовнішніх URL у модулях Joomla через phpMyAdmin

Зверніть увагу на поле published: значення 0 означає, що модуль вимкнено. Наявність URL у такому модулі ще не означає, що посилання реально з’являється на сторінках сайту. Старі рекламні, партнерські та підписні модулі можуть роками залишатися в базі у вимкненому стані.

Як побачити лише ті посилання, які реально виводяться в браузері

База даних показує, де URL зберігається. Але щоб зрозуміти, чи присутнє посилання на конкретній відкритій сторінці, зручніше перевірити DOM через консоль браузера.

Відкрийте потрібну сторінку сайту та запустіть інструменти розробника одним зі зручних способів:

  • F12 — відкрити DevTools, потім перейти на вкладку Console;
  • Ctrl + Shift + J — одразу відкрити Console у Chrome, Edge або Opera;
  • Ctrl + Shift + I — відкрити DevTools, потім вибрати вкладку Console;
  • натиснути правою кнопкою миші по сторінці та вибрати «Переглянути код» / «Дослідити елемент» (назва пункту залежить від браузера), після чого перейти на вкладку Console.

Після відкриття Console вставте наступний код і натисніть Enter:

JavaScript — Console браузера
console.table(
  [...document.querySelectorAll('a[href]')]
    .map(a => {
      const u = new URL(a.href, location.href);
      return {
        text: a.textContent.trim().replace(/\s+/g, ' ').slice(0, 80),
        url: u.href,
        domain: u.hostname,
        rel: a.rel || ''
      };
    })
    .filter(x =>
      /^https?:/.test(x.url) &&
      x.domain !== location.hostname
    )
);

У таблиці будуть видимі текст посилання, повний URL, домен і значення rel. Якщо результат порожній, це означає, що на відкритій сторінці немає зовнішніх клікабельних посилань <a href>.

Пошук зовнішніх посилань на сторінці Joomla через Console браузера

Такий спосіб особливо корисний для перевірки конкретної проблемної сторінки: URL може зберігатися в базі або кеші, але не виводитися відвідувачеві.

Пошук конкретного домену у файлах Joomla через ISPmanager

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

В ISPmanager відкрийте Менеджер файлів → Пошук файлів, вкажіть корінь сайту або конкретну папку, увімкніть:

  • Шукати в підкаталогах;
  • Шукати за вмістом;
  • у полі «Маска вмісту» — потрібний домен, наприклад example.com.

Пошук зовнішнього домену за вмістом файлів Joomla в ISPmanager

Якщо пошук по всьому сайту знаходить домен лише в каталогах cache або administrator/cache, це ще не доказ впровадження в PHP-код. Кеш може містити збережену копію матеріалу або сторінки, де таке посилання було звичайною частиною тексту.

Зовнішнє посилання знайдено лише в кеші Joomla

Щоб знайти першоджерело, додатково перевірте каталоги /templates, /components, /modules і /plugins. Якщо там збігів немає, а домен знаходиться лише в кеші, спочатку шукайте його в матеріалах і модулях бази даних.

Чому не можна видаляти все, де трапляється base64_decode

base64_decode() — звичайна функція PHP для декодування Base64. Вона може використовуватися й нормальним кодом Joomla або розширень. Тому сам факт її наявності не доводить зараження.

Небезпечний підхід — знайти всі входження base64_decode і видалити їх. Так можна пошкодити робочий компонент, авторизацію, передавання параметрів або іншу штатну функцію.

Правильніше діяти навпаки:

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

Як безпечно видалити небажане посилання

Спосіб залежить від джерела:

  • Матеріал Joomla — видаліть або виправте посилання в редакторі матеріалу.
  • HTML-модуль — відредагуйте або видаліть модуль через адмін-панель.
  • Налаштування розширення — спочатку перевірте параметри компонента, плагіна або модуля.
  • Файл шаблону або розширення — зробіть резервну копію та порівняйте файл із чистим оригіналом. Якщо код невідомого походження, безпечніше замінити розширення його офіційною чистою версією, ніж вирізати фрагменти навмання.

Як ставитися до звичайних зовнішніх посилань

Видаляти всі зовнішні посилання заради SEO не потрібно. Google рекомендує посилатися на корисні зовнішні джерела, коли це допомагає читачеві. Звичайне редакційне посилання не потребує nofollow. Для реклами та платних розміщень бажаний rel="sponsored", для користувацьких посилань — ugc, а nofollow застосовують, коли ви не хочете пов’язувати свій сайт із ресурсом.

Докладніше: рекомендації Google щодо вихідних посилань.

Підсумки

Для перевірки зовнішніх і прихованих посилань у Joomla 5 і 6 необов’язково встановлювати окремі програми. Практична послідовність виглядає так:

  1. знайти зовнішні URL і домени в матеріалах через phpMyAdmin;
  2. перевірити HTML-модулі та їхній стан публікації;
  3. на конкретній сторінці подивитися реально виведені посилання через Console;
  4. якщо домен підозрілий — знайти його за вмістом файлів в ISPmanager;
  5. відокремити кеш від реального вихідного коду;
  6. видаляти лише підтверджену небажану вставку, а потім повторити перевірку.

Такий підхід допомагає не лише знайти справді зайве посилання, а й не пошкодити сайт випадковим видаленням нормального коду.

Add comment

Знайшли помилку або неточність?

Выделите фрагмент текста и нажмите Ctrl + Enter. Также можно воспользоваться кнопкой ниже.

Знайшли помилку або неточність?

Виділений фрагмент буде додано до повідомлення автоматично. За потреби додайте пояснення.

Форма захищена від автоматичних надсилань

Дані використовуються лише для перевірки та виправлення матеріалу.