Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.
Предыдущая часть цикла — Учимся делать редиректы в nginx.
Следующая часть цикла — Делаем бэкапы.
Вообще я не любитель использовать PMA (здесь и далее — PhpMyAdmin). Он не умеет ничего такого, чего нельзя было бы сделать в консольном mysql, а местами даже умеет меньше. Но на чужих серверах ставить его всё же приходится.
Вообще, прежде чем наживать себе геморрой на задницу, посмотрите на «легкую» альтернативу PMA — https://www.adminer.org/. Он, в буквальном смысле, состоит из одного файла (раньше были стили в отдельных файлах, но сейчас всё вроде в один положили). Хоть и проблемы обеспечения безопасности у вас будут почти те же и всю статью прочитать всё же придется, но с adminer-ом всё же немного попроще. Да и кодовая база меньше, уязвимостей меньше.
Перейдем к проблемам безопасности, с которыми нам придется бороться.
Во-первых PMA (и adminer, само собой) обязаны работать только по https. Иначе любые данные, передаваемые в браузере (а это и пароли к базе, и её содержимое) у вас смогут перехватить в открытой сети. Ну или провайдер заинтересуется. Или по СОРМ-у нагрепают нужный пароль. Впрочем, с https мы уже справились в прошлых частях, так что тут всё просто. Здесь же важно понимать, что HTTP-протокол туповат и редиректа на https там, куда приходят POST-запросы, недостаточно (данные-то по http будут отправлены).
Во-вторых, очень важно понимать, что в PMA находили достаточно уязвимостей, которые можно было эксплуатировать без авторизации в mysql (честно говоря я не помню сколько, но и одной достаточно). Да и сам торчащий голой жопой PMA в ситуации, когда пароль от базы могут достать где-то ещё, вынуждает задуматься о том, что мы катимся не туда. В общем, PMA (и adminer тоже, куда ж без него), обязательно необходимо убирать за дополнительную авторизацию. Я ниже рассмотрю авторизацию по IP и http basic auth.
В третьих, PMA — излюбленная цель для CSRF-атак. В чём их суть. Если кто-то проникнет на ваш сервер (сами по ssh пустите или php-шелл зальют), то можно будет обращаться с самого сервера в http://127.0.0.1:8080 (или где у вас там апач). И если настраивать ограничение доступа к PMA на уровне nginx-а — то мы оставляем лазейку для скрипт-киддисов. И если с большинством CMS/CMF эта проблема не очень актуальна, то для PMA (с учетом абзаца выше) такая проблема — весьма критична. Поэтому ограничения мы будем реализовывать на уровне apache (через htaccess-файл) и конфиге самого PMA, дабы человек, добравшийся до возможной CSRF-атаки, не получил доступа к PMA.
Теперь об установке. Для дебианщиков есть 2 более или менее «правильных» способа установки PMA. Первый — пойти на сайт phpmyadmin.org, скачать архив и положить в каталог определенного домена на сервере. Такой способ работает только на вашем первом сервере, с которого вы сдуваете пылинки. Как только у вас появляется второй — вы забиваете на обновление установленного таким образом PMA и он обрастает мхом.
Мы будем ставить из пакета. Хотя бы периодически вы запускаете apt-get upgrade, тогда и PMA будет обновляться.
Ну, поехали. Ставим пакет:
Когда у вас будут спрашивать, какой у вас веб-сервер, выбирайте стрелочками apache2, нажимайте пробел, и только потом нажимайте tab и enter (а то задавали мне уже вопрос на эту тему, чего PMA не поставился из пакета). Потом у вас спросят что-то в духе «Configure database for phpmyadmin with dbconfig-common?», отвечаем Yes.
«Password of the database’s administrative user» — наш пароль от рута в mysql (мы его ещё в .my.cnf сохраняли, дабы не протерялся).
«MySQL application password for phpmyadmin» — пароль для базы самого PMA. Вообще он нам больше не понадобится, так что скопируйте туда любые 100 символов из случайного места в интернете. Дважды (потом подтверждение спросят же).
На этом в общем-то установка закончена и наш уютненький сервер радостно торчит огромной дыркой в безопасности на весь интернет. Ну а радостные роботы-сканеры эту дырку уже нашли и пытаются в неё чем-нибудь потыкаться. Здесь бы и статью закончить, но зачем я тогда лишних 600 слов писал? Давайте исправлять.
Для начала выбираем URL, по которому в будущем будет доступен наш PMA. Да, можно, конечно и оставить /phpmyadmin на всех доменах (как это организовано по умолчанию), но это не наш путь.
Допустим, у нас fqdn у сервера host.example.com. Допустим, у нас свободен наружу порт 7443. Допустим, мы сможем запомнить /pma-is-bad в качестве uri. Чудесно, будем селить по урлу https://host.example.com:7443/pma-is-bad
Для начала заведем конфиг в nginx (напомню, что сертификат мы уже получили, а nginx немного настроили). Заводим файл /etc/nginx/sites-available/phpmyadmin7443.conf (опять же, смысл написанного в этом файле можно посмотреть по ссылкам в предыдущих скобках).
server {
listen 7443 ssl default;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/cert.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
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_session_cache shared:SSL:64m;
ssl_session_timeout 28h;
location / { return 444; }
}
# Здесь и далее - server{} для домена, на котором будет работать PMA.
server {
listen 7443 ssl;
server_name host.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/cert.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_prefer_server_ciphers on;
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_session_cache shared:SSL:64m;
ssl_session_timeout 28h;
# location для самого PMA, проксируем запросы к нему в apache:
location /pma-is-bad {
proxy_pass http://127.0.0.1:81;
proxy_redirect http://127.0.0.1:81/ /;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
# запросы к файлам .htaccess/.htpasswd на всякий случай фильтруем и здесь тоже.
location ~ /\.ht {
return 404;
}
# остальные запросы тоже молча дропаем:
location / { return 444; }
}
Не забываем сделать симлинку в sites-enabled и рестартнуть nginx:
Следующий конфиг, который нам интересен, это /etc/apache2/conf-enabled/phpmyadmin.conf
Ищем в нём строку:
И меняем на (опять же, /pma-is-bad меняйте на то, что сами придумали):
Так же где-то в блоке «<Directory /usr/share/phpmyadmin>» (можно следующей строкой, например) добавляем такую строчку:
Эта строчка разрешает использовать файлы htaccess в /usr/share/phpmyadmin (дада, all не очень безопасно, только вот писать в /usr/share/phpmyadmin может только рут).
Рестартим апач:
Теперь пора положить .htaccess файл в /usr/share/phpmyadmin/.htaccess
AuthType Basic
AuthName "PMA"
AuthUserFile /usr/share/phpmyadmin/.htpasswd
Require valid-user
Заводим пользователя для basic-авторизации (команда htpasswd запросит пароль для пользователя):
Собственно, команда htpasswd -n генерирует строчку из username и хэша его пароля. -B — указывает, что для генерации хэша нужно использовать bcrypt-функции (судя по ману, сейчас это самый безопасный вариант в плане перебора пароля по хэшу). При помощи >> мы записываем сгенерированную строку в нужный нам файл (указанный в .htaccess).
Чтобы удалить пользователя — просто удаляем его строку из .htpasswd, чтобы сменить пароль — удаляем строку, а потом генерируем новую. Кстати, сменить username, не меняя пароля, можно тупо поменяв его в файлике.
Сама строчка выглядит для username с паролем 123 примерно вот так:
Если есть возможность (статический адрес или хотя бы подсеть у админов, которым нужен доступ в PMA) — очень хорошо будет ограничить доступ к PMA по IP-адресам. Например, так (всё в том же /usr/share/phpmyadmin/.htaccess):
deny from all
# можно указывать подсети
allow from 192.168.0.0/24
# или отдельные адреса
allow from 10.0.0.23
В любом случае, неплохим решением будет запретить доступ с локалхоста в PMA:
Ну и ещё, если вы не заморачивались с запретом location /pma-is-bad на каждом сайте, есть смысл сделать редирект для тех, кто попадёт в PMA по какой-то «левой ссылке» (через другой домен, например):
RewriteCond %{HTTP_HOST} !^host\.example\.com$ [NC,OR]
RewriteCond %{REQUEST_URI} !^/pma-is-bad [NC]
RewriteRule (.*) https://host.example.com:7443/pma-is-bad [R=301,L]
Само собой, примеры htaccess-а выше можно комбинировать друг с другом в одном файле. Ну и если кто забыл — то рестартить апацхе после изменений в .htaccess-файлах не нужно.
+1 к adminer (если уж оно вообще надо)
С возвращением!
P.S. ждем бакапы. В теории, это вообще должна была быть 2ая статья по счету :)
Бэкапы следующая будет точно. На следующей неделе в тудушник закинул.
> С возвращением!
спасибо