В посте про взлом я 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 и почему «регулярно обновляйтесь» больше не работает.
Комментарии (0)
Пока нет комментариев — будьте первым.