среда, 23 октября 2019 г.

Sendmail. Принудительная / обязательная smtp-аутентификация. Правила (Rules) конфигурационного файла.



Принудительная / обязательная smtp-аутентификация sendmail. Правила (Rules) конфигурационного файла.
Настраивая sendmail столкнулся с довольно непонятной по современным меркам ситуацией: фактически любой пользователь (внешней сети или внутренней) может от имени  сервера рассылать спам!!! То есть, хотя бы так:
> telnet MyDomainSendmailServer.com 25
> ehlo MyDomainSendmailServer.com
> Mail from:<serg@MyDomainSendmailServer.com>
> RCPT To:<BillGates@microsoft.com>
> Data

(конечно, надо знать чей-то ящик домена, который засветился в сети)
В принципе, всё по стандартам и вполне логично. Ведь сотрудник может работать не только на самом предприятии через локальную сеть, а может куда-то уехать в другую страну, и захочет иметь доступ к почте. Что же тогда делать, как бороться если кто-то начнет таким образом рассылать тысячи спам-писем из нашего домена??? А ответа нормального похоже не существует. Если почтой пользуются только на рабочем месте, то еще можно что-то настроить через relay. Но когда кто-то должен пользоваться smtp-сервером из вне, то ситуация плачевная. Есть, конечно, разные способы борьбы, хотя бы вставлять паузы перед приглашением (greet_pause), но такая защита курам на смех. Единственный логичный вариант, чтобы при отправке письма запрашивало пароль. Это и есть smtp-авторизация. Как её настраивать можете найти в Интернете – ресурсов хватает. Но в этом способе есть критические недостатки, которые фактически нивелируют всю проделанную работу:
1) smtp-авторизация не является обязательной. То есть, если вы и не прошли авторизацию, то можно и без неё.
2) Можно настроить сервер с обязательной авторизацией:  DAEMON_OPTIONS(`..., m=a’)
Однако, тогда ни один сервер не сможет прислать почту на ваш домен. Ведь стороннему серверу (gmail/mail.ru/yandex.ru) нужно ввести какой-то пароль…

В Интернете нарыл способ конфигурационным файлом создать принудительную авторизацию. И этот способ, похоже, является единственной надеждой. Попросту странно, что это не входит в базовые конфигурации серверов электронной почты. Говорят, что такое манипуляции могут пригодиться раз в жизни – настроил и забыл, но если это нужно всем, зачем же тогда изобретать велосипед каждому? И так, код:
LOCAL_CONFIG
Ksyslog syslog
LOCAL_RULESETS
SLocal_check_rcpt
# empty address?
R<>                     $#error $@ nouser $: "553 User address required"
R$@                     $#error $@ nouser $: "553 User address required"

#Добавляем адрес отпрвителя
R$*            $: $1 $| $&f

#Канонизируем адреса
R$* $| $*             $: $2 $| $>Parse0 $>3 $1
R$* $| $*             $: $2 $| $>Parse0 $>3 $1

#Ксли отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$+<@$=w.>  $|  $+<@$=w.>              $: $>CheckLocalAuth

#Другие варианты fqdn-адресов пропускаем (внеш-внеш, внутр-внеш, внеш-внутр)
R$+<@$+>  $|  $+<@$+> $@ $1

#Алиасы, MAILER-DAEMON и др. лок. получатели без доменной части - в ту же проверку
R$+ $| $+                $: $>CheckLocalAuth

#Контрольная проверка - кто там не охвачен нашими правилами:  если сработает - покажешь, подправим
R$*                     $: $(syslog syslog:PROBLEM: $1 $) $1

SCheckLocalAuth
#Почту  с самого сервера пропускаем
R$*                   $: $&{client_addr}
R127.0.0.1                   $@OK

#Если авторизация имела место - пропускаем
R$*                     $: < $&{auth_authen} >
R< $+ >                 $@ OK

#Все остальное блокируем
R$*   $#error: $: 553 Sorry, you must use smtp-authentication. Please, contact to postmaster.

Пояснение кода
Долго пытался понять, что этот весь код выше означает. Оказалось, что на русском языке даже нет документации по этим командам (лишь частичную)! Пришлось качать заграничную Costales B., Jansen G., Aßmann C. «sendmail».
До конца весь код я сам не понял, но то, что именно нам нужно - поясню.  Но начнём с основ.

Ликбез
Каждое правило (Rules) начинается с буквы «R». Затем идут так званые левое поле и право поле. Они должны быть разделены табуляцией (это обязательно). Работают правила так: В некой памяти (назовём её WorkSpace) находится какая-то информация. Эта информация сравнивается с шаблоном левого поля, и если совпадение осуществилось, то в WorkSpace записывается то, что в правом поле. Пример:
Допустим WorkSpace=xxx
И имеем правило:
R xxx yyy
Так как WorkSpace совпадает с шаблоном «xxx», значит в WorkSpace будет помещено «yyy».  То есть, на языках программирования это выглядит приблизительно так:
If WorkSpace==xxx then WorkSpace=yyy
Или, в общем случае:
If WorkSpace==LeftPattern then WorkSpace=RightField
Как забить изначальные данные в WorkSpace – вопрос интересный.  В данном выше коде smtp-авторизации в WorkSpace будет содержаться адрес электронной почты получателя. Но для обучения можно создать файл test.cf с таким содержимым:
V10
STest
R xxx     <TAB>        yyy
(в первой строке мы указываем версию, в принципе, это не обязательно. Во второй строке указываем названием раздела).
Теперь в командной строке вводим:
> sendmail -btC test.cf
Вводим название раздела и изначальные данные WorkSpace:
Test  xxx
Будет выведено такое:
Test    Input:  xxx
Test    Returns: yyy
(Выход: Ctrl+D)
То есть, наши изначальные введенные данные (WorkSpace) совпали с шаблоном «xxx», поэтому правило вернуло результат «yyy». Если бы ввели другие изначальные данные, было бы:
Test    Input:  xxxс
Test    Returns: xxxс

Пояснение кода smtp-аунтентификации:
1. LOCAL_CONFIG
Ksyslog syslog
Здесь связано с логированием
2. LOCAL_RULESETS
SLocal_check_rcpt

Называем наш раздел Local_check_rcpt. По этому имени его можно вызвать для тестирования через sendmailbt. Однако, не советую. Лучше использовать для тестирования либо отдельный файл, либо через сообщения об ошибках (будет сказано в конце статьи).

3. # empty address?
R<>                     $#error $@ nouser $: "553 User address required"
R$@                     $#error $@ nouser $: "553 User address required"
Смотрим что из себя представляет адрес получателя электронной почты. Если там только угловые скобки или еще какая-то [хрень], то выдаём сообщение об ошибке. Как именно работает эта строка, углубляться не будем. Она почти стандартная.
4. #Добавляем адрес отправителя
R$*            $: $1 $| $&f
Эта строка сложная и требует многих пояснений.
1) знак $* означает шаблон равный 0 или более токенов. Под токеном подразумевается некое слово ограниченное специальными символами. Например, xxx@yyy – два токена. По сути, одиночное использование шаблона $* означает то же, что и «*» при поиске имён файлов. А в данном случае, такой паттерн используется, чтобы в любом случае выполнилось правое выражение. То есть, что-то вроде if TRUE then…
2) знак $: означает, что данное правило выполнится один раз. У Sendmail есть заморочка, что правило должно работать некоторое количество раз, эдакое зацикленное выражение. Рекомендую всегда использовать $:, разве что вы знаете, что делаете.
3) В выражения $1, $2, $3 и т.д. записывается то, что было найдено при использовании шаблона. То есть, при поиске на совпадение  xxx.yyy.zzz:
R $-.$-.$-                             $1 $2 $3
($- означает строго один токен)
Мы имеем $1=xxx, $2=yyy, $3=zzz
4) $| одна из тех команд, что используются часто, но описания на них нет… Она представляет собой что-то вроде буфера обмена, чтобы можно было какие-то данных сохранять и использовать в следующих командах.
Пример:
R $*       $: $| asdf
R $| asdf            zzz

В первой строке: мы в любом случае записываем в «буфер обмена» четыре букы asdf
Во второй строке: смотрим, есть ли в буфере обмена четыре буквы asdf. И если есть, то в WorkSpace записываем zzz.
5) $&f –адрес отправителя.
То есть, команда «R$*            $: $1 $| $&f» означает: отработать 1 раз; в WorkSpace записать то, что есть ($1 – в нашем случае адрес получателя), а в буфер записать адрес отправителя.
5. #Канонизируем адреса
R$* $| $*             $: $2 $| $>Parse0 $>3 $1
R$* $| $*             $: $2 $| $>Parse0 $>3 $1
Это одна из тех строк, которые сложны для начального понимания. Слева видно, что шаблон смотрит есть ли что-то в WorkSpace и в буфере обмена. Справа же, с помощью $> идут вызовы других кусков конфигурационного файла. В результате работы этих двух строк наши оба адреса (получателя и отправителя) будут в каноническом виде: user<@domain.com.> (обратите внимание на точку в конце имени домена!)
Надо сказать, что если один из адресов идёт без домена (просто имя пользователя), то с ним никаких изменений не произойдёт.
6. #Ксли отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$+<@$=w.>  $|  $+<@$=w.>              $: $>CheckLocalAuth

Здесь, собственно мы и проверяем формат адресов на совпадение с нашим доменом.
$=w выдаст наш домен.
$+ означает один и более токенов.
То есть, наше условие выглядит где-то так: if (WorkSpace==”serg<@MyDomainSendmailServer.com.>”) and (Bufer==” anna<@MyDomainSendmailServer.com.>”) then CALL CheckLocalAuth. А CheckLocalAuth идёт ниже.
7. #Другие варианты fqdn-адресов пропускаем (внеш-внеш, внутр-внеш, внеш-внутр)
R$+<@$+>  $|  $+<@$+> $@ $1

Здесь уже мы не смотрим принадлежат ли адреса нашему домену или нет. Лишь бы было похоже на адреса электронной почты (канонические).
Знак $@ (когда он в правой колонке) означает, что мы прекратим работу этой подпрограммы. Не забываем, что весь тот код мы будет встраивать. Вот таким образом, мы просто прервём выполнение наших действий, и отдадим управление другим командам конфигурационного файла.
8. #Алиасы, MAILER-DAEMON и др. лок. получатели без доменной части - в ту же проверку
R$+ $| $+                $: $>CheckLocalAuth

То есть, бездоменные адреса электронной почты тоже отправим на проверку в CheckLocalAuth
9. #Контрольная проверка - кто там не охвачен нашими правилами:  если сработает - покажешь, подправим
R$*                     $: $(syslog syslog:PROBLEM: $1 $) $1

Идёт запись в системный лог-файл.
10. SCheckLocalAuth
Вот, собственно и процедура по проверке на smtp-аутентификацию.
11. #Почту  с самого сервера пропускаем
R$*                   $: $&{client_addr}
R127.0.0.1                   $@OK

$&{client_addr} возвратит ip-адрес отправителя. И запишется он в WorkSpace.
Следующей строкой сравнится WorkSpace с адресом 127.0.0.1, и если они совпадут, то выполнится прерывание процедуры $@.
12. #Если авторизация имела место - пропускаем
R$*                     $: < $&{auth_authen} >
R< $+ >                 $@ OK

$&{auth_authen} запишет в WorkSpace информацию про авторизацию.
И следующей строкой посмотрим есть ли в WorkSpace что-то (не пустота). Если есть, значит, авторизация была, всё хорошо, и опять завершаем работу процедуры.
13. #Все остальное блокируем
R$*   $#error: $: 553 Sorry, you must use smtp-authentication. Please
, contact to postmaster.
Если мы добрались сюда, значит, наш адрес не был 127.0.0.1 и авторизации не было, поэтому выдаём сообщение об ошибке.
Debug (отладка) через сообщения об ошибках
Кстати, через $#error можно делать debug команд. После подозрительной или не правильно работающей команды можно прописать:
R$* $| $*   $#error: $: WorkSpace=$1 Buffer=$2
Дабы видеть содержимое WorkSpace и буфера. Эти ошибки можно будет видеть либо через telnet либо через клиент электронной почты.

Дальнейшая доработка
Но вышеприведенный код тоже имеет недостатки! Пункт 6:
#Ксли отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$+<@$=w.>  $|  $+<@$=w.>              $: $>CheckLocalAuth
То есть, здесь идёт проверка в том случае, если спамер буде рассылать письма из «засвеченного» адреса в локальную сеть (т.е. оба адреса локальные)! А если спамер, как вначале статьи, захочет спамить во вне?
Поэтому, предлагаю следующий вариант:
#Ксли отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$*  $|  $+<@$=w.>              $: $>CheckLocalAuth
То есть, независимо какой адрес получателя, мы всё равно отправим на проверку.
Далее, в разделе CheckLocalAuth теоретически можно убрать проверку на ip. Просто удалить две строки, которые описаны в пункте 11. Но тогда служебные письма от сервера не будут доходить до к вашему второму служебному ящику. Либо как-то сервер настроить, чтобы и он проходил smtp-авротизацию.

Всё, теперь в любом случае, если кто-то захочет слать письмо от вашего домена, ему необходимо будет ввести smtp-пароль к ящику.

четверг, 21 июня 2018 г.

Установка Magento 2 на базе LAMP-сервера Debian

Установка Magento 2.2.4 на базе LAMP-сервера Debian

Установка Debian 9.4.0 x64 (CD-образ с xfce)

[сама установка Debian пропущена, первоначальная установка идёт без сети, зато с рабочим столом]
Настройки:
  1. Когда Интернет настроен, в файл /etc/apt/sources.list добавляем строку:
# Nano sources.list:
deb ftp://ftp.ru.debian.org/debian stable main contrib non-free
# apt update
  1. # apt install mc (если нужно)
  2. В окне консоли: Правка-настройки на последней вкладке установить флажки на быстрые клавиши (то есть, отключить их).
  3. # apt install apache2
  4. Проверяем, запускается ли web-сервер. Открываем FireFox и набираем 127.0.0.1
  5. Создаём папку: # mkdir /var/www/magento
В неё надо распаковать скачанный архив magento (Magento-CE-2.2.4_sample_data-2018-05-01-09-43-25.zip)
Например:
# unzip Magento-CE-2.2.4_sample_data-2018-05-01-09-43-25.zip -d /var/www/magento
  1. В папке /etc/apache2/sites-available создаём файл имеющий название как и домен с нашим сайтом + слово «.conf», например: aaa.bbb.conf с таким содержимым:
<VirtualHost *:80>
ServerName aaa.bbb
ServerAlias www.aaa.bbb
DocumentRoot /var/www/magento
<Directory /var/www/magento>
Options -Includes -Indexes -ExecCGI
AllowOverride All
</Directory>
</VirtualHost>
Регистрируем сайт: # a2ensite aaa.bbb
Перезагружаем apache: # systemctl reload apache2 или # service apache2 reload
  1. Так как виртуальные хосты создаются на одном ip адресе, то проверить наш сайт вбив в браузер ip-адрес не получится. Нужно обязательно вводить имя: например, aaa.bbb. Но в нашем случае такого реального адреса не существует на DNS-серверах, придётся нам вписать его в файл /etc/hosts:
127.0.0.1 aaa.bbb
127.0.0.1 www.aaa.bbb
Если хотите сделать чтобы сайтом по умолчанию был наш, тогда можно удалить текущую заглушку:
# a2dissite 000-default
Конечно, если у нас будет несколько виртуальных хостов, тогда надо будет еще чего настроить.
Не забудем перегрузить апач.
  1. Проверяем работу web-сервера. Создаём в папке /var/www/magento файл index.html с таким содержимым:
<html>
Hello world
</html>
Вводим в браузере: aaa.bbb/index.html
(из-за опции AllowOverride All, которая разрешает использовать файл настроек .htaccess, в котором жестко прописан index.php нам пришлось вручную дописать index.html).

И, возможно, надо изменить права на этот файл (см. пункт 12).
  1. Устанавливаем php: # apt install php7.0 (вместо «php7.0» можно использовать «php» и будет установлена текущая актуальная версия PHP)
  2. Создаём в папке /var/www/magento файл index2.php с таким содержимым:
<?php
phpinfo();
?>
Вбиваем в браузере aaa.bbb/index2.php (должна отобразиться информация о PHP)
(возможно, перед этим следует перезагрузить Апач)
  1. Файлам в /var/www/magento скорее всего надо дать права пользователя www-data:
# chown -R www-data:www-data /var/www/magento/
  1. Устанавливаем DOM: # apt install php7.0-dom (нужно для корректного запуска установки magento). Необходимость в нём была выяснена в процессе поиска ошибок трудных. Перезагружаем Апач.
  2. Теперь можно запустить установку Магенто (хотя бы для того, чтобы узнать его требования к системе). Вводим в браузере aaa.bbb (теперь уже не надо вводить index.php)

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





В принципе, я мог бы и не показывать всех этих ошибок, а просто заранее сказать, какие надо установить расширения. Однако не исключено, что у вас будут другие ошибки, и вы будете более-менее знать, как с ними бороться.
С версией PHP нам повезло. Иначе пришлось бы ставить другую версию, возможно качая с официального сайта. Но это уже выходит за рамки этой кратчайшей инструкции.
Вторую ошибку GD пропустим, она сама собою исправится после установки модулей.
Теперь удовлетворим требования к расширениям PHP:
  1. # apt install php7.0-curl
# apt install php7.0-gd
# apt install php7.0-mcrypt
# apt install php7.0-intl
# apt install php7.0-mbstring
# apt install php7.0-pdo-mysql
# apt install php7.0-soap
# apt install php7.0-zip
# apt install php7.0-bcmath

Перезагружаем Апач, опять вводим в браузер aaa.bbb и опять смотрим на проверку требований к ПО. На этот раз у меня всё нормально.


  1. Чтобы можно было продолжить дальнейшую установку нам еще необходимо установить MySQL:
# apt install mysql-server
И на всякий случай: # apt install php7.0-mysql
  1. Установим популярный клиент к базе: # apt install phpmyadmin. Если спросит для какого сервера – укажем apache. Введём пароль «1». Добавим пользователя под которым будем заходить в phpmysql:
# mysql -u root -p (спросит пароль – у нас: 1)
> create user 'пользователь'@localhost identified by 'пароль'; (пароль в кавычках)
> grant all privileges on *.* to 'пользователь'@localhost;
> grant grant option on *.* to 'пользователь'@localhost;
> flush privileges;
> quit;
Заходим в панель, вводим в браузере: aaa.bbb/phpmyadmin
Выберем нужный язык, пользователь и пароль те, которые вы придумали чуть выше.

Я завёл пользователя sqluser.
Создаём базу для Магенто: выбираем Создать БД. Имя базы, например, magento_db. Сравнение: utf8_general_ci:


Жмём кнопку «Создать», и в общем-то всё. Таблиц добавлять не надо. Система Магенто сама будет делать то, что ей нужно. Можно нажать кнопку «выход» (она под надписью phpMyAdmin).
  1. Возвращаемся к установке Магенто, теперь после проверки конфигурации можем продолжить и ввести данные для доступа к базе данных:

  1. Следующий шаг можете оставить как есть:

  1. Подправляем часовые пояса и язык.
  2. Создаём пользователя для входа в саму систему Магенто.
  3. Приступаем к инсталляции…
Иногда инсталляция может остановиться на каком-то проценте. Возможно, надо для php увеличить настройки memory_limit и max_execution_time. О них даже упоминается в файле php.ini.sample, который находится в папке magento.
Вообще, существует способ установить магенто и без браузера. Ищите в Интернете информацию о командной строке начинающуюся на php bin/magento setup:install
  1. Когда закончится инсталляция, надо нажать на кнопке «Launch magento admin»

  1. Возможно отобразится ошибка 404, и хз что делать :)
  2. Однако aaa.bbb покажет наш магазин. Если он без стилей, то попробуйте выполнить эти команды находясь в папке /var/www/magento:
# php bin/magento setup:static-content:deploy -f ru_RU en_US (ключ -f так как без него не хочет работать).
# php bin/magento indexer:reindex

Если установка была прервана, то возможна потом проблема с MySQL. Поэтому, лучше найти вручную папку с базой данных magento_db и удалить её. Обычно расположение этой папки указано в файле /etc/mysql/mariadb.conf.d/50-server.cnf опция datadir.