Александр Куртеев
← Все материалы

Рассылка, которой я управляю голосом с телефона. И почему я больше не держу её на Joomla

15 мин чтения Александр Куртеев 7
Рассылка, которой я управляю голосом с телефона. И почему я больше не держу её на Joomla

В посте про взлом я Joomla я рассказал, что пользовался ей ради конструктора лэндингов и из-за мощного инструмента рассылок — AcyMailing.

К слову сказать, Acymailing мой любимый инструмент рассылки на протяжении более 10 лет.

  • Миллионы писем были отправлены через него.

  • Курс по Асимаилинг прошли почти 3000 человек

  • Мы командой перевели на асимаилинг порядка 300 крупных клиентов с базами 80000 - 500000 человек.

И вот, я принял решение, что больше ни в одном проекте у меня не будет джумлы и вордпресс (темболее) ради безопасности.

Что делать с лэндингами я решил. И стало гораздо круче и удобнее, чем было раньше. А вот рассылка гораздо более сложный механизм. Но, в целом, имея большой опыт и самостоятельно пользования и внедрения и решения все возможных проблем с рассылкой, архитектура инструмента рассылки в моей голове умещается. Решил сделать свой рассыльщик.

Для начала я проанализировал Acymailing. Столько лет любил, надо же под конец понять, вдруг есть проблемы.

И вот, что я обнаружил.

Безопасность

Справка

Что такое CVE — на всякий случай

CVE — это всемирный каталог найденных дыр в программах. Нашли уязвимость — ей выдают номер вида `CVE-2026-56292` и оценку опасности от 0 до 10. Всё это публично: любой человек вбивает номер в поиск и читает, что именно сломано и в каких версиях.

Здесь и заключается неприятность. Публикация номера — это одновременно и предупреждение вам, и инструкция всем остальным. По данным Patchstack, о которых я писал в прошлый раз, от публикации до первых массовых атак проходит в среднем пять часов. Не недель. Часов.

Оценка выше девяти означает «ломается удалённо, без пароля, с полным доступом». Такие дыры сканируют автоматом по всему интернету.

Три дыры за 2026 год

Март, оценка 8.8. Повышение прав. В коде стояла проверка с условием «пропустить проверку прав, если в имени задачи встречается слово Ajax». Любой зарегистрированный на сайте человек — да хоть ученик, которого вы сами и завели, — мог обойти проверку, завести подписчика с чужим идентификатором и войти администратором.

Июль, оценка 9.2. Самое неприятное. Данные из адреса страницы подставлялись прямо в запрос к базе без обработки. Вход — обычная публичная страница сайта, никакого пароля не нужно. Читается любая таблица: учётные записи Joomla вместе с зашифрованными паролями, содержимое сайта, настройки всех расширений.

Сентябрь, оценка 7.5. Чтение произвольных файлов с сервера, снова без пароля. Работает при включённой опции «встраивать картинки в письмо». Затронуты все версии по 11.0.4 включительно, а опубликовали это на прошлой неделе.

Совет

если у вас стоит AcyMailing — обновитесь прямо сейчас и заодно выключите встраивание картинок в настройках. Это дело пяти минут и оно закрывает свежую сентябрьскую историю.

Разработчик, надо отдать должное, каждый раз выпускал исправление быстро. Вопрос не в том, чинят ли. Вопрос в том, сколько таких находок ещё впереди — и успеете ли вы обновиться в те самые пять часов.

Мастер-ключ, который уезжает в каждом письме

Это я нашёл сам, читая код.

В каждой установке AcyMailing есть один секретный ключ на тридцать символов. Он создаётся при установке и не меняется никогда. Этим ключом отключается защита от роботов на формах подписки — проверка видит его в адресе страницы и отвечает «проверка пройдена» ещё до того, как что-либо проверит. Им же авторизуется публичный вывод любого модуля Joomla по номеру. Им же заполняется поле ключа планировщика в настройках.

И он же дописывается в ссылку внутри рассылаемого письма.

То есть: подпишитесь на любую рассылку школы — или получите от кого-нибудь пересланное письмо — и мастер-ключ установки у вас в руках. Ломать ничего не надо, достаточно посмотреть на ссылку.

Ссылка отписки, которая умеет удалять

В каждом письме есть ссылка отписки. В ней лежит четырнадцатисимвольный ключ подписчика — без срока действия, навсегда.

Этим одним ключом делается семь разных вещей: подтвердить подписку, отписаться, отписаться от всего, открыть профиль, сохранить профиль, выгрузить все персональные данные подписчика и удалить его запись целиком.

Письмо живёт в почтовом ящике годами. Пересланное письмо живёт в чужом ящике столько же.

Ящик отлупов как пульт отключения

Отлупы — ответы почтовых серверов вроде «такого адреса не существует». AcyMailing читает их из обычного почтового ящика. И складываются три вещи:

  • ящик принимает письма от кого угодно, а его адрес виден в служебных полях любого вашего письма;

  • подписчика ищут по принципу «любой адрес, найденный в тексте письма», побеждает первый попавшийся;

  • проверки «а мы вообще отправляли этому человеку это письмо» нет нигде.

Дальше арифметика простая. Письмо с подходящим текстом плюс адрес жертвы — минус один подписчик из вашей базы. Тысяча писем — минус тысяча подписчиков. И вы даже не поймёте, что произошло: в интерфейсе это будет выглядеть как обычные отлупы.

Интуитивно, когда я первый раз увидел, что база с 70000 человек похудела до 40000, я стал рекомендовать осторожно пользоваться чисткой базы по отлупам.

Спам

Самая дорогая часть, потому что она бьёт не разово, а постепенно и по всем письмам сразу.

С 2024 года Gmail, Yahoo и Mail.ru считают по отправителю долю жалоб — сколько человек из тысячи нажали «это спам». В Постмастере Google эта цифра так и называется, Spam rate. Порог — 0,3%, то есть три человека на тысячу. Перешагнули — письма перестают доходить, причём не только рекламные, а вообще все, включая пароли и доступы к курсу.

Вот что AcyMailing делает с этой цифрой.

Отписка в один клик не работает по-настоящему. Кнопка «Отписаться» рядом с адресом отправителя в Gmail появляется, только если письмо соблюдает определённые правила. У AcyMailing эти правила не выполняются ни в одной конфигурации: подпись письма по умолчанию выключена, а служебные заголовки отписки добавляются не при сборке письма, а как побочный эффект вёрстки — не поставили ссылку отписки в теле, и заголовка в письме тоже нет.

Человек, который хочет перестать получать письма, не находит удобную кнопку. И нажимает «спам». Это прямой рост той самой доли жалоб.

Служебная пометка «массовая рассылка» не ставится нигде. Её прямо требует Mail.ru. Её отсутствие означает ещё и то, что ящик отлупов принимает чужие автоответчики наравне с настоящими отчётами о недоставке.

Жалобы почти не доходят обратно. Почтовые сервисы умеют сообщать отправителю «на это письмо пожаловались» — по-английски это называется FBL. Из четырнадцати способов отправки, которые поддерживает AcyMailing, эти сообщения умеет принимать один.

Остановки по жалобам нет. Ни одной проверки доли отлупов и жалоб в коде отправки не существует. Рассылка по испорченной базе доедет до конца, сколько бы жалоб ни прилетело по дороге.

Вывод

За 10 лет я был в спаме всего несколько раз. Но вот на пограничные ситуации эти инструменты могут сильно повлиять, чтобы сберечь репутацию.

Отлупы

Работают. Но устроены так, что лучше бы не работали — потому что неработающую систему замечаешь, а эту нет.

Ящик читается с самого старого конца. Позиция чтения нигде не сохраняется. Убрать письмо из будущих выборок можно только удалив его физически. За один заход разбирается не более ста писем, заходы раз в шесть часов.

Что происходит, когда непонятых писем накапливается больше лимита: разбор новых отлупов прекращается полностью. Планировщик при этом продолжает отчитываться об успешной работе. Вы смотрите в отчёт, там всё хорошо, а мёртвые адреса копятся в базе месяцами.

Стандартный формат отчёта о недоставке — тот, который отдаёт любой нормальный почтовый сервер, — не разбирается вообще. Письмо схлопывается в одну строку текста и прогоняется через семнадцать регулярных выражений, которые администратор вписывает руками.

Ответ сервера в базу не сохраняется никогда. Дата получения отлупа — тоже: колонки под неё просто нет в таблице. То есть на вопрос «почему вот этот адрес заблокирован и когда» ответить по базе невозможно в принципе.

И отдельно: порог мягких отлупов работает не как «три подряд», а как «три за всю жизнь подписчика». Сброса при успешной доставке нет. Человек три раза за пять лет был в отпуске с переполненным ящиком — и выбыл из базы навсегда.

Скорость

В целом скорость Асимаилинг устраивает. Мы доводили рассылку до скорости 60000 писем в час. А сам я остановился на отправке 10000 писем в час.

Важно понимать, что параметры крутить можно сколько угодно. В определенный момент упираемся в то, что события подготовки писем и отправки идут параллельно и это сильно нагружает сервер.

Тут еще есть много костылей связанных с паузами между письмами и параллельными отправками. Итогом становится то, что при росте мощности сервера скорость отправки увеличивается слабо.

Над скоростью я особо не заморачивался, но сейчас, забегая вперед, скажу, что при правильной архитектуре скорость отправки увеличивается в десятки раз, при этом не нагружая систему.

Сегменты. А вы точно уверены в выборке?

Этот пункт я бы поставил первым по практическому вреду, просто он менее эффектный.

Когда вы в интерфейсе выбираете сегмент и видите число получателей, происходит вот что. Система проходит по всей таблице подписчиков и дописывает каждому подходящему служебную пометку. Потом выбирает всех помеченных. Потом вторым проходом пометку снимает.

На базе в полмиллиона это два обновления полумиллиона строк — на каждый показ числа. Кэша нет: посмотрели число, выгрузили список, поставили в очередь — база переписалась три раза.

Но главное не скорость. Главное, что пометок всего три штуки на всю систему, и они общие: предпросмотр в админке и постановка рассылки в очередь пользуются одними и теми же. Отсюда два сценария, которые я разобрал в коде до конца.

Недобор. Вы открыли редактор сегмента в тот момент, когда рассылка ставилась в очередь. Пометки снялись под работающим процессом. В рассылку попала часть аудитории. Кампания при этом помечена отправленной. Заметить нечем — цифра «отправлено» будет соответствовать тому, что попало в очередь.

Перебор. Пометки от вашего предпросмотра попали в выборку планировщика. Письмо ушло людям вне сегмента.

Если у вас когда-нибудь рассылка уходила «не тем» или до людей не доходило то, что вы точно отправляли, и вы списали это на себя — возможно, это были не вы.

Доказательство согласия на рассылку

Закон о рекламе устроен так, что доказывать наличие согласия должен отправитель. Не жалобщик доказывает, что не подписывался, а вы доказываете, что он подписывался.

Что AcyMailing может предъявить в качестве доказательства: галочку «подтверждён» и дату.

  • Текст согласия, под которым человек подписался, не хранится нигде ни в одной таблице.

  • IP-адрес момента подписки в десятой версии убрали совсем.

  • У ссылки подтверждения нет срока жизни: письмо, отправленное год назад на адрес, который с тех пор сменил владельца, всё ещё создаёт «доказательство согласия».

  • Режим импорта «считать всех загруженных сразу подтверждёнными» включён по умолчанию.

Вывод

галочки мало. Доказательство — это текст согласия в той редакции, дата, IP и источник подписки. Галочка говорит только «согласие было», а закон просит показать, на что именно человек соглашался.

Проанализировав Асимаилинг я сперва сделал те же возможности, что и в Acy, только решив все его проблемы

Сначала я решил все проблемы Acymailing

Проанализировав Асимаилинг я сперва сделал те же возможности, что и в Acy, только решив все его проблемы.

  • Заголовки отписки собираются при сборке письма, из служебных полей, а не из вёрстки. Заголовок не может «не появиться» из-за того, что дизайнер переставил блок. Кнопка отписки в Gmail работает — и человеку не нужно жать «спам».

  • Отписка отрабатывает мгновенно — без промежуточной страницы «вы уверены?» и без переходов. Повторное нажатие ничего не ломает.

  • Ссылка отписки умеет только отписывать. Выгрузка и удаление персональных данных по ссылке из письма не делаются в принципе.

  • Ни одно письмо из очереди не удаляется. Очередь — это одновременно снимок аудитории и журнал: всегда видно, кому что ушло и что с ним стало. Письмо берётся в работу так, что два процесса физически не могут взять одно и то же.

  • Отлупы и жалобы разбираются по стандарту, ответ сервера и время события сохраняются. Причём классифицируем по смыслу ответа, а не по коду: «отклонено как спам» не закрывает живой адрес, потому что это разговор о репутации, а не мёртвый ящик.

  • Стоп-лист — отдельный список адресов, а не галочка на подписчике. Удалили подписчика — стоп-лист всё равно помнит. Проверяется дважды: при постановке в очередь и ещё раз перед самой отправкой, потому что между этими моментами человек успевает отписаться.

  • Сегмент считается чтением. Никаких пометок в таблице подписчиков, никакого общего состояния между предпросмотром и отправкой.

  • Каждый процент показывается со знаменателем, и если данных мало, процент не показывается вовсе. Никаких нарисованных графиков при отсутствии данных.

  • Согласие хранит текст, под которым человек подписался, дату, адрес и источник. Это то, что можно приложить к ответу в надзорный орган.

А потом началось интересное

Решил погулять на славу и реализовать всё, что хотел.

  • Репутация. Меня напрягало постоянно проверять репутацию в постмастерах. Сейчас все сразу внутри. Подключены Постмастеры Google и Mail.ru: доля жалоб, доля писем с верной подписью, репутация домена — всё на главном экране.

  • Спам. Аналитика по почтовым сервисам сразу показывает где открывают меньше всего

  • Аналитика пути письма. Почтовые сервисы запрашивают информацию об отправленном письме. У меня сейчас хранится вся информация вместе с исходником письма.

  • Обработка всех отлупов. База чистится сама. Ничего не удаляется, но к каждому пользователю добавляются все пояснения.

  • Несколько шлюзов для отправки. Можно отправлять как со своего сервера, так и подключить внешний, например, SMTP.BZ. Например, идет релиз, попали в спам, переключились на другой шлюз и успешно завершили релиз.

  • Каналы. Асимаилинг предлагал отправлять только письма. Я расширил, добавили Телеграм, Макс, SMS. Естественно, для каждого канала

  • Воронки. Реализовал не просто серии писем, а полноценный мультиканальные воронки со всей аналитикой и сложной сегментацией.

  • Служба поддержки. Человек отвечает на письмо или в бота ТГ и ответ сразу в админке, на который можно написать ответ.

  • Плюс еще десятки полезных мелочей: удобный конструктор письма, встроенный (мой) умный редактор изображений и их ужимальщик (очень бесило в нескольких местах обрабатывать изображения и сжимать), анализ содержимого письма перед отправкой, генератор внешних форм, интеграции с попуярными сервисами (амо, битрикс, тильда, гк) и многое другое

И то, ради чего всё в итоге затевалось. Я внедрил MCP, т.е. к рассылке подключается ИИ (Claude, чатгпт) — любой обычный ИИ, без подсчета токенов и прочих оплат.

В результате, я управляю рассылкой с телефона голосом. Еду в машине и надиктовываю:

  • сделай письмо про то-то, вот тезисы,

  • поставь рассылку на такую-то аудиторию и вычти вот эту аудиторию

  • сделаем в моем дизайне.

Итог через 5 минут:

  • Написана рыба письма

  • в моем дизайне

  • выстроена нужная аудитория

  • запланирована отправка

Сажусь за компьютер, правлю текст и выставляю статус на отправку.

Здесь важно не перепутать. Это не «ИИ пишет за меня тексты» — тексты я пишу сам, иначе их незачем читать. ИИ заменил технаря, которым я раньше был собирал вёрстку, чистил списки, сводил отчёты и отвечал на вопрос «а сколько там получателей». Всё скучное, из-за чего рассылка откладывалась на «сделаю на следующей неделе».

Вывод

Экономия 3-4 часа рутинных действий на отправке одной рассылки.

Общая мысль

В прошлый раз я закончил тем, что главный риск сайта — не «плохая CMS», а количество чужого кода, который вы не читали и не контролируете.

С рассылкой это та же мысль, только ставки выше. Лендинг можно перезалить за вечер. База подписчиков утекает один раз и навсегда, и вместе с ней утекает ваше доказательство того, что все эти люди на неё подписались.

Я держал рассылку на расширении пятнадцать лет и ни разу не открыл его исходники. Открыл — и за три недели нашёл всё, что выше. Не потому что я специалист по безопасности, я им не являюсь. Потому что я туда не смотрел и не думал, что можно сделать круче.

Joomla и Wordpress массово взламывают

С чего всё началось: нас взломали, и я разобрал на цифрах, почему ломают Joomla и WordPress и почему «регулярно обновляйтесь» больше не работает.

Александр Куртеев
Александр Куртеев
Соавтор платформы School-master, создатель и экс-владелец Joomla.center

18 лет обучаю техническим инструментам для онлайн-бизнеса.

Telegram

Новые разборы — сразу в Telegram

Публикую здесь и в канале одновременно. В канале — короче и с закулисьем.

Комментарии (0)

Пока нет комментариев — будьте первым.