Пора валить! Часть вторая. 2020

Это про жопу по смене хостинга(ов), а не места жительства, если чего. 😉

Было уже пять лет назад. И вот опять…

За полтора месяца третий раз сервер по Европе носил.

Что характерно, в третий раз всё прошло намного проще и техничнее. Но пару ремарок для себя будущего оставлю. Мало ли чего… 😉

1-ый раз

В первый раз засвирбело ради ZimaBudet.ru и её wordpress –приспичило включить PHP7. Поддержка хостёра тогдашнего (sinaro) сказала: проще новый сервер поднять и переехать.

Я скрипел, я пыхтел и матерился, но переехал с одного VPS на другой у одного и того же хостёра. Был недоволен собой из-за этой вот заварки, но как оказалось напрасно: тяжело в учении – легко в бою! 😉

2-ой раз

Сажусь однажды с утра за комп, а там хуяк – хвалёный мною sinaro.host не резолвится и не пингуется сам и не резолвит мои сайты.

Бэкапы свежие, ясен-красен, остались на непингуемом сервере. Жопа, как она есть – мрак, теснота и пахнет неприятно.

Судорожно нашёл какого-то хостёра – CORETEK ★ ★ ★ RU, вспомнил, что делал неделю назад. Сутки с лишним стресса – переехал. Сайты в итоге около 10 часов были “вне зоны действия сети”. Остальное время что-то всё время подкручивал: что сам вспоминал, на что юзера указывали.

Синаро на мои вопросы “шозанах” так и не отреагировал. Включился почти через сутки. Разослал всем “Извините, можете две недели работать без оплаты”.

Идите тоже в жопу!

И через пару дней они пошли! Приходит письмо от админа:

Следом приходит второе: извините, админ мудак и уволен, мы продолжаем светить лететь. Через пару дней звезда (или это была планета?..) синаро потухла. Аминь.

Мы же продолжаем наше парение полёт…

3-ий раз

С коретеком не срослось и через месяц я укатил к FoxCloud ★★★★★.

Пока всё супер! Дали IP из разных подсетей, подарили панель ISPManager Lite, предложили хорошую цену. Саппорт решает оперативно.

А, ну может быть интерфейс перегруженный и баннеры навязчивы. Неприятный звоночек – ага, противопоказание – нет.

Как будет по факту – жизнь покажет. Веду наблюдение. 😉

С коретеком первый звоночек прозвенел почти сразу, когда я попросил прописать PTR записи к своим IP для rDNS. Просьба выпала на выходные и поскольку “там сейчас никого нет” записи появились только почти через двое суток.

Ооокей, пацаны. Допустим.

Потом потекли воскресные дни, когда просыпаешься и стабильно находишь всплеск нагрузки CPU на серваке, а в ящике россыпь уведомлений “Сервер был в дауне 3… 8… 12… минут”. В первую неделю саппорт морозился – это чего-то у вас. Потом – да, что-то с бэкапами, поправим. Потом – это всё панель, не мы. Потом – !наверное! что-то с железом, но это не точно, давайте вы переедете и посмотрим.

А давайте! Я переехал. Но, извините, пацаны, не к вам. 😉

Лирики хватит. Дальше…

Практика переезда

Итак, несколько полезных штук, к которым пришёл вот в эти итерации (не самый продвинутый парень, ага 😉 )

  1. Открыл для себя DNS хостинг. Приземлился на HE Free DNS. Пробовал наш NetBreeze (клёво, что три сервера в разных частях света), но побоялся забыть через год продление сделать. 😉 Cloudflare – шикарный (клауды по миру, анти-DDoS), но для коммерческих продуктов – платно.
  2. Нахер rsync! 😉 С сервака на сервак клёво переезжать с помощью ISPManager. Заезжает всё и сразу: www, почта, БД. Важный нюанс – сделать владельцем для www-папки нужного www-пользователя. Иначе посыпят ошибки переноса и шалость не удастся.
  3. Проверка email на антиспам традиционно здесь (free – 3 раза в день). Настройка rDNS – через хостёра, а вот HELO smtp сервера, если это Exim делается охренеть огненно для каждого IP вот так, а ещё лучше с ifaces:

    /etc/exim/exim.conf :
    remote_smtp:
    driver = smtp
    helo_data = ${lookup dnsdb{ptr=$sending_ip_address}{$value}{$primary_hostname}}
  4. Если, блин, вдруг не работает Gyazo для безусловного https-сервера или активация софта, то не тупи, а добавь условие для перехода http->https 😉

    if ( $request_uri !~ "^/gyazo")
    {
    return 301 https://$host:443$request_uri;
    }

PHP левелап (5.x ==> 7.x). Проблемы и решения

Вордпресс давно горит красненьким: обновите свой PHP. Ну и хрен с тобой — гори!

Но тут, как беременному, приспичило селёдки перевести WP-сайты на статику и убрать WP с сервера. А модный плагин WP2Static в открытую шантажирует – работаю только на PHP 7.

Ну давай, блин, обновляться!..

Начал с локальной машины, где всё крутится на Denwer 3 (A2.2.22, P5.3.13, M5.5).

Сначала накатил PHP 5.6.19 + Apache 2.40 отсюда и затем повысил PHP до 5.6.40 из архива дистрибутивов по этой инструкции (ну а вдруг?! 😉 ). Вордпресс не оценил.

Оокей! Едем дальше.

Тогда старый сервер отправил в архив и перешёл на новую сборку Denwer (Apache 2.4, PHP 7, MySQL 5.7).

Вордпресс обновился, WP2Static подтянулся, тестовый сайт загнал в статику.

Супер, чо!

Но голос капитана Зелёного в моей голове:

И понеслась… 😀

Запуск OpenGoo 1.3.1 в 2019

Нежно люблю дерево задач из древнего OpenGoo.

В своё время искал, перепробовал многое, но остановился на этом комбайне, из которого юзаю одну только функциональность – дерево задач.

Оно умеет назначать задачи разным юзерам, выращивать их деревом, создавать шаблоны из выращенных деревьев.

Мне удобно делать релизы и публикации по чеклисту из шаблонов, накидывать туда все списки дел, дробить их на подзадачки и потом с наслаждением удалять их по мере выполнения. 😉

Хреновина ресурсоёмкая, по нагрузке на сервер не супер-оптимизированная, насколько я могу судить по периодическому 500 ответу сервака.

Но вот привык.

А на новом сервере оно не взлетело.

Суть, как и во многом далее – в использовании в OpenGoo устаревшего драйвера mysql (который в PHP7 выпилили) и отсутствие обратной совместимости с новым mysqli, который идёт с PHP 7.

ОКей, починяю этот примус и запускаю древнючий OpenGoo 1.3.1 в 2019 году 😉 :

    1. Перевёл все обращения к MySQL базе под формат mysqli. Для этого установил на сервер скрипт, путь к директории – относительно сервера:
      /home/бла-бла-бла/convert
    2. Указал в конфиге OpenGoo использовать mysqli адаптер, вместо mysql. По инструкции:
      define('DB_ADAPTER', 'mysqli');
    3. Ну и собсно добавил сам адаптер-класс в папку
      /opengoo/environment/library/database/adapters

И оно завелось (на самом деле нет).

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

Запуск GeoIP для PHP5

yum install php-pear gcc make php-devel – установит php-pear пакет для компилирования исходников

yum install GeoIP GeoIP-data GeoIP-devel – установит пакеты geoip

pecl install geoip – соберёт PECL библиотеку geoip.so
echo "extension=geoip.so" > /etc/php.d/geoip.ini – включит библиотеку после рестарта апача.

Если есть альтернативный PHP (у меня это PHP 7.3), то под него собираем свой модуль:

/opt/php73/bin/pecl install geoip-1.1.1 – соберёт PECL библиотеку geoip.so

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

Как применить антиспам фильтр Thunderbird ко всем учётным записям сразу

А никак!

Антиспам фильтры в Thunderbird пишутся отдельно для каждой существующей учётки. И чтобы один и тот же фильтр работал для них для всех, фильтр придётся создавать в каждой учётке заново.

У меня в Thunderbird заведено 8 учётных записей. Есть фильтр по содержанию в теме. В нём что-то около 30 стопслов. Я приуныл, осознав, что придётся заново воссоздавать его ещё в семи учётках. Погуглил на эту тему…

И да, есть способ проще – скопировать фильтры из одной учётки в другую!

Как скопировать антиспам фильтр в Thunderbird

Суть в том, что файл с фильтрами (msgFilterRules.dat) создаётся отдельно для каждой учётки в её папке (ThunderbirdFolder\Data\profiles\ImapMail\MailServerName) и для локальной папки (ThunderbirdFolder\Data\profiles\Mail\Local Folders).

Остаётся в текстовом редакторе скопировать нужный фильтр (ограничен строками name= и condition=) из учётки, где он уже настроен в остальные учётки:

 

Можно конечно и сам файлик скопировать, но бывает что у разных учёток есть свои уникальные фильтры, поэтому такой способ не всегда хорош.

Ещё нюанс. Скопировал фильтр, а оно при запуске пишет – “фильтр не работает, потому что файл не читаем, Thunderbird создал новый”. 

Воттакак?!

Оказалось проблема с кодировкой (в стопсловах есть кириллица). Некоторые учётки используют Windows-1251, а некоторые UTF-8. Перевёл правила в UTF-8 и всё поехало, как надо.

Осталось два вопроса. Если кто даст ответ – будет здорово!

  1. Что за хрень с кодировками в разных учётках? Подозреваю из-за этого не работает и поиск по архивам сообщений.
  2. Как указать в Thunderbird, чтобы он отфильтрованные сообщения килял прямо на сервере, не подгружая локально и не тратя мой мобильный трафик?

 

Полуавтоматическое продление сертификатов Let’s Encrypt

Минуло 90 дней или все гвозди забиваем в последний день. 😉

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

Оказалось всё просто:

  • открываем консоль. Я открываю из Bitvise SSH, потому что NetBox для FarManager, к сожалению, виснет
  • переходим в директорию с установленным certbot. У меня это httpd-cert в директории с web-юзерами
  • выполняем команду ./certbot-auto renew

Это всё. Оно само прошлось по созданным ранее сертификатам и обновило их и ключи:Да, не понял почему, но вызов certbot-auto без ./ вызывало ошибку command not found. Так что их наличие – это важно!

…надо бы в cron команду прописать, но что-то стало лениво – впереди для этого целых 90 дней! 😀

NB: И, блин, перезапусти после этого Nginx!

service nginx restart

А то ключи новые лежат, а сервак браузеру старые отдаёт, сайты недоступны, а ты – тормоз.

Я взломал вашу MySQL базу. Доброжелатель

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

На скринах, в обрезанном интерфейсе неизвестной мне программы, были данные из базы одного из моих проектов.

Дениса занервничал. 😁

Темой безопасности и уязвимостей на сайтах, признаться, никогда особо не интересовался. Слышал, что-то конечно про SQL-injection, что-то читал про DDoS , но в голову не брал. А тут нате вам – приплыли.

Пришлось пройти и этот квест.

Причина, кстати, в расπздяйстве (фильтруйте и проверяйте параметры в URL) и закономерному при этом наказании — MySQL-инъекции. 😉

Взламываю свою базу данных MySQL

Поломана MySQL-база. Значит там и проблема. Это раз.

Данные в интерфейсе какой-то программы с обрезанным названием. Значит процесс автоматизирован. Это два.

Загуглил про SQL-инъекции и вот оно – то, что нужно. Статья старая, но расписано как надо и в картинках для чайников. Стало понятно, как злоумышленник запускает нужные SQL-запросы – через оператор UNION, прилепляемый к параметру в URL страницы сайта.

Открыл сырые логи сайта — ~500 обращений к сайту с IP моего доброжелателя с использованием этой конструкции:

Здесь можно бы и остановиться — причина понятна, пофиксить и забыть.

Да, но нет!

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

Безуспешно гуглил по всякому, а когда отчаялся и решил искать комплексные решения анализа уязвимостей сайта, в рекомендациях Netsparker’а увидел знакомый скриншот…

SQLi Dumper – та самая программа для поиска и взлома уязвимых баз данных MySQL.

Как оказалось, с этой программой, процесс взлома «дырявых» баз и просмотр данных из них доступны любому идиоту. Софтина сама находит дураков и показывает их данные в пару кликов.

У меня цель была другая – исследовать свой сайт.

Вставил URL с параметром из логов, нажал GO и GoToDumper, когда она немного потрепавшись с сервером нашла уязвимость. Потом Get Databases, Get Tables, Get Columns, Dump Data. И да, вот они мои данные, полученные через backdoor:

Блокирую взлом базы данных MySQL

Суть взлома, как по книжке: параметр из URL (это ID поля из базы) без проверок и фильтров прямиком идёт в SQL запрос. Злоумышленник через оператор UNION цепляет к нему свой SQL запрос и сервер его послушно выполняет.

То есть вместо валидного обращения к новостной статье #314:

https://apasscracker.com/news/shownews.php?newsid=314

получается запрос:

https://apasscracker.com/news/shownews.php?newsid=314999999.9' union all select 1,2,3,4,5,[t],7,8,9,10,11,12,13 and '0'='0

которым SQLi Dumper и раскручивает базу дальше.

Поскольку, по логике алгоритма, ID – это всегда целочисленное значение, то закрыть эту конкретную дырку элементарно — просто в скрипте явно приводим полученный из URL параметр к целочисленному значению:

$id=intval($id);

Всё!

Теперь, когда в параметре ожидаемое целое число, скрипт отработает, как задумано — покажет новость; когда в параметре непонятная херня вместо цифры, скрипт завершится с ошибкой, а мои волосы останутся шелковистыми и без дополнительной седины. 😉

Вместо эпилога

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

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

PS: и ещё прочтённый за эти дни ништячок — как узнать, что сервер DDoS’ят.

#жизньболь. Спонсор рубрики – Google

Жил-да-был я с мультидоменным сертификатом от StartSSL с датой окончания – Апрель 2018-ого. Все домены компании прописал в один серт и для всех сайтов довольный использовал.

Удобно. Красиво. И не дорого.

От новости осени 2016-ого, что Chrome и Firefox будут банить сертификаты StartSSL и WoSign моложе 21 октября отмахнулся: мой-то в апреле получен, а в 2018-ом по тамошним реалиям подсуечусь.

Но сегодня, после обновления Vivaldi открываю свой хэлпдеск и не могу:

И так с бубном поплясал, и эдак – ноль. Пошёл читать гугль про гугль.

На форуме поддержки Google Chrome наткнулся на разъяснения: с Chrome 56 вырежем серты моложе 21 октября, а с Chrome 57 и более ранние выпиливать начнём.

Похоже на правду: из всей пачки,прописанных в сертификате доменов, валидным для Chromium 57 остался один, самый старый. Остальные – ERR_CERT_AUTHORITY_INVALID

Вот такая #жизньболь случилась при поддержке гугли. 😉

UPD: В группе SWRUS на Facebook (тьфу, прости господи!) посоветовали Let’s Encrypt. Запилил по быстренькому новых сертификатов.

Работает. Но выглядит скромнее. 😐

Вид с сертификатом Let's Encrypt

И да, бля, мне скудоумному не понять: StartSSL/WoSign с платными сертификатами и проверками – рассадник зловредов и фишеров, а летсэнкрипт – типа белые джедаи для котяток и белочек.

Ладно, пофиг…

Костыли для Let’s Encrypt:

wget https://dl.eff.org/certbot-auto

chmod a+x certbot-auto

/certbot-auto certonly –webroot –agree-tos –email [email protected] -w /home/my/site/www/ -d my-domain.ru -d www.my-domain.ru

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

А ещё больше понравилась официальная инструкция. Запердолил для nginx и [почти] всё. Научить бы еще ISPManager по умолчанию ключи /etc/letsencrypt/live/ использовать… Но, сука, лень. Руками в конфигах меняю.

И да, после этого Nginx рестартануть надо:

service nginx restart

Хотя, есть мнение, что это не правильно. Правильно так:

service nginx reload

Тогда нет риска, что сервис выключится и не сможет включится, а с ним и все сайты. oO

Полёт продолжается… 😉

Как через ISPManager прикрутить к доменам SSL сертификат от StartSSL

Валидация пройдена, единый EV-сертификат для целой пачки доменов выпущен StartSSL.

Как его прилепить к сайту-то?

  1. Сохраняем нужный сертификат на диск из списка доступных сертификатов: startssl-01В результате на диске образовался ZIP-файл с пачкой crt-файлов с набором буковок под всякие сервера (Apache, Nginx, IIS, Other). Я работал с архивом для Apache – взял оттуда файлик ИМЯДОМЕНА.crt. У меня это получился passcovery.com.crtИ тут я, в лучших традициях склеротика, подзавис – а где у меня приватный ключ для этого сертификата-то?..

    Решение нашлось в смутных воспоминаниях прошлых лет и составленных на их основе запросах к гуглю… 🙂

    Может быть оно не оптимально и вообще через *опу, но вот как есть. :))

  2. Импортируем сертификат ИМЯДОМЕНА.crt в хранилище сертификатов Internet Explorer: startssl-02
  3. И тут же экспортируем этот сертификат в формате .pfx и дополнительно указываем, что хотим экспорт с приватным ключом:

 

Я ему: “Exim, pipe email в скрипт и в почтовый ящик!” А он такой: “Mail delivery failed!”

Как уже писал, входящие ордера у меня идут на псевдо-email. Exim отправляет поток в скрипт и передаёт письмо дальше на реально существующий email.

Получается, что данные и в базу автоматом заносятся, и письмо я получаю о приходе ордера.

И вот оно “поломалось”…

То есть с моей стороны всё работало, как надо, а вот отправителю от сервера приходил привет вида:

SUBJ: Mail delivery failed: returning message to sender

BODY:
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:

  pipe to |/var/www/scrpts/gvmmny.php
    generated by [email protected]

The following text was generated during the delivery attempt:

------ pipe to |/var/www/scrpts/gvmmny.php
       generated by [email protected] ------

PHP Warning:  Module 'geoip' already loaded in Unknown on line 0
Works! OrderID: 63838534

blah-blah-blah

Сразу как-то не дошло, в чём проблема. Пришлось интернеты ихние читать…

Суть в том, что скрипт и вся его обвязка не должны ничего генерировать в поток. А у меня получалось, что и скрипт (в тестовых целях) чего-то своё писал, и варнинг от PHP прилетал.

Решение:

  1. Задисабил свой текст.
  2. Задисабил подключение модуля в php.ini (;extension=geoip.so), поскольку он уже в сборке самого PHP присутствует (потому и варнинг).

И всё снова стало хорошо: и база пополняется, и я письма получаю, и отправитель отлупов от моего сервера не видит.

Опять делаю SSL A-класса. Теперь на Nginx

Резал пуделя, когда был на говнохостинге от Битвеб. Тогда это был патч для апатч.

ssltestaСейчас, на Sinaro, сервер работает в связке Apache+Nginx и пришлось в общем-то тоже самое (отключать SSL3 и запрещать слабые алгоритмы шифрования) делать в конфиге Nginx (/etc/nginx/nginx.conf):

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2;
ssl_prefer_server_ciphers on;

Потом рестарт и всё пучком.

service nginx restart

Серт брал у китайского WoSign. C дешёвого GoGetSSL переключилось всё хорошо. Работает. 🙂

 

Частичный редирект http -> https в Nginx

Отломалась активация софта.

Вскрытие показало, что проблема в редиректе http->https, сделаному средствами Nginx:

listen 185.48.58.35:80;
return 301 https://$host$request_uri;

В браузере всё пучком, а из программы ключ активации запрашивается по http, идёт редирект и ответа она уже не видит.

Решение очевидно в общем-то – закрыл редирект в условие:

listen 185.48.58.35:80;
if ($request_uri !~ “^/diracti”)
{
return 301 https://$host$request_uri;
}

То есть редиректим всё, кроме того в чьём URI есть нужная папка (тут это / diracti)

Рестарт Nginx: service nginx restart и всё, как надо.