python

Nginx: защищаем урл одноразовым паролем

  • суббота, 19 сентября 2015 г. в 02:11:10
http://habrahabr.ru/post/267095/

Появилась задача обезопасить админскую часть на сайте. Причём это надо было сделать без внесения изменений в код самого сайта. Лучшее, что смог я найти — oauth2_proxy и nginx-google-oauth, но они требовали обработку коллбэков. Эти решения мне не понравились и я их отверг.

Пришлось обратиться к одному из модулей nginx и комплектующим для велосипеда.

Т.к. я не являюсь программистом, то с радостью приму замечания по моему маргарин-коду. И так. Я набросал простое приложение.

Пример установки будет на основе Debian/Ubuntu.

Установка:

# установим nginx  с поддержкой модуля ngx_http_auth_request_module 
nginx -V 2>&1 | grep -qF -- --with-http_auth_request_module && echo "OK" || sudo aptitude update && sudo aptitude install nginx-extras
# клонируем репозитарий
git clone git@github.com:loukash/otp-auth.git  # или git clone git@bitbucket.org:loukash/otp-auth.git
# установим все зависимости
cd otp-auth
pip install -r requirements.txt

Настройка приложения:

# создадим базу пользователей
python manage.py initdb
#  добавим пользователя
python manage.py useradd -l test

Последняя команда выдаст что-то подобное:
Scan QR: http://2qr.ru/otpauth://totp/OTPAuth:test1?secret=LOS5VMN5WI3FUTE4&issuer=OTPAuth
Or add manually SECRET KEY: LOS5VMN5WI3FUTE4
Emergency codes: 39816948,88908661,07327337,95159743,24616032

Добавляем это в ваш OTP-генератор. Я думаю, что у вас уже установлен Google Authentificator или подобное. Если же нет, тогда придётся установить. Тут помощь от Гугла. При добавлении пользователей генерируются ещё и резервные коды, на случай, если вы потеряете свой телефон.

Переходим к настройке nginx. Для выбранного location надо добавить:

location /private {
  ...
  auth_request /auth;
  error_page 401 /login;
  ...
}

А эти location делают авторизацию:

location = /auth {
  internal;
  proxy_pass_request_body off;
  proxy_set_header Content-Length "";
  proxy_pass http://127.0.0.1:5000;
}

location = /login {
  proxy_pass http://127.0.0.1:5000;
}

Запускаем наше приложение и рестартуем nginx:

sudo service nginx reload
python manage.py runserver

Теперь при открытии site.name/private вы увидите страницу ввода одноразового пароля:

image

Что реализовано:

  • Проверка одноразового пароля
  • Управление пользователями
  • Резервные коды

Что в планах:

  • Сделать приложение настраиваемым
  • Демонизация
  • Логгирование