Debian.pro

Про Debian


Большой Мануал, часть 25: логгируем вызовы mail() из php.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.

Предыдущая часть цикла — Боремся с вирусней на сайтах.

Следующая часть цикла — Not yet published


Исторически большая часть вирусни для php занимается именно тем, что шлёт спам. Навскидку я бы оценил количество этой вирусни в половину от всей. Поэтому логгирование вызовов mail() сильно сокращает время на поиск активной части вирусни. Да и просто для дебага «почему письмо не шлется» удобно. Тем более, что в php с версии 5.3 всё же прикрутили неплохое логгирование, которое указывает конкретный php-файл и строчку, где был вызов.

Но, сами понимаете, если бы всё было просто, статью писать я бы не стал. Лог-то прекрасно пишется, если просто включить настройку mail.log, но пишется он от имени пользователя, под которым запущен сам скрипт (соответственно, под апачем скорее всего www-data). А если каждый сайт под своим пользователем? Соответственно, все мануалы пестрят чем-то вроде «создайте файл /var/log/php-mail.log, сделайте chmod 777″. В принципе, незачем читать его кому-либо, кроме рута и группы adm, как это принято для всех логов, куда может попасть приватная инфа.

Поэтому отправлять лог мы будем не в файл, а в syslog. Что характерно, официальная документация на php.net об этом не напоминает, да и вообще пришлось поискать, как такое сделать (сначала я пытался сделать mail.log = /dev/log). В итоге, конечно, ничего сложного.

Сначала создаём каталог и файл для лога (вообще каталог не обязательно, я для аккуратности):

root@server:~# mkdir /var/log/php-mail/; chown root:adm /var/log/php-mail/; chmod 750 /var/log/php-mail/
root@server:~# touch /var/log/php-mail/mail.log; chown root:adm /var/log/php-mail/mail.log; chmod 640 /var/log/php-mail/mail.log

Далее заводим ini-файл для php, который включит логгирование (я пишу пример для apache, для fpm/cli просто положите по аналогии в соответствующие каталоги). Для php 5.X в debian файл следует поместить в /etc/php5/apache2/conf.d/90-mail-log.ini, для php7.0 — в /etc/php/7.0/apache2/conf.d/90-mail-log.ini, для 7.2 (если у вас пакет от Ondrej) — в /etc/php/7.2/apache2/conf.d/90-mail-log.ini
Содержимое файла (можете, в принципе, вписать в сам php.ini, но это не всегда удобно):

mail.log = syslog

Далее настраиваем rsyslog (он стоит по умолчанию в debian, для остальных сами гляньте, как откладывать в файл строчки по вхождению), чтобы нужная нам информация попадала в отдельный лог. Кстати, сойдёт за пример, как писать отдельный лог для любых строчек с каким-либо вхождением (в данном случае — «mail()»). Например, в файл /etc/rsyslog.d/99-php-maillog.conf

:msg, contains, "mail() " /var/log/php-mail/mail.log
& ~

Почти всё, остаётся только написать конфиг для logrotate, чтобы случайно не забить всё место. Ротировать будем при достижении файлом определенного размера (size 100M). Пишем, например, в /etc/logrotate.d/php-mail

/var/log/php-mail/mail.log {
    rotate 7
    size 100M
    copytruncate
    create 0640 root adm
    compress
    missingok
    notifempty
}

Всё, осталось только отрестартить нужные демоны:

root@server:~# apachectl restart
root@server:~# service rsyslog restart

Теперь у нас есть лог, в который могут писать любые сайты вне зависимости от пользователя, под которым сайт работает. Прочитать этот лог могут только root и пользователи группы adm, а сам лог изредка ротируется.
Строчки в логе будут выглядеть примерно так:

May 22 14:27:49 dev apache2: [22-May-2018 14:27:49 UTC] mail() on [/home/dev2/data/www/some_file.php:18]: To: example@example.com -- Headers:
21.06.2018 byinkvizitor68sl|big-manual

Комментарии (2):

  1. yukra :

    Стоит добавить:
    1) Полезно так же выставить mail.add_x_header в true. Так в самом тексте письма будет добавлено имя файла, который сгенерировал это письмо и UID пользователя.
    2) Если у вас таки есть желание отдать логи пользователю, то можно писать что-то типа ‘mail.log = «${HOME}/logs/mail.log»‘. Можно ли так же настроить logrotate с ходу не скажу, но в крайнем случае можно для logrotate генератор конфигов написать.

  2. > 1) Полезно так же выставить mail.add_x_header в true. Так в самом тексте письма будет добавлено имя файла, который сгенерировал это письмо и UID пользователя.
    Как раз не полезно, information disclosure.
    А в логе всё то же самое будет.

Написать комментарий