Появилась задача обезопасить админскую часть на сайте. Причём это надо было сделать без внесения изменений в код самого сайта. Лучшее, что смог я найти — 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

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

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

Что в планах:

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

Комментарии (13)


  1. lolipop
    17.09.2015 22:27
    -5

    А почему не гитхаб?


  1. ToSHiC
    17.09.2015 23:53
    +1

    Кажется, вы забыли requirements.txt положить в гит.


    1. lukashin
      18.09.2015 07:26

      Исправил.


  1. Spoofi
    18.09.2015 11:04
    -1

    Как раз недавно задумывался подобное сделать для себя. Теперь задача упрощена, спасибо за статью!

    P.S. не думали перенести репозиторий на GitHub? Мне кажется, там больше активного комьюнити, чем на bitbucket.



  1. Chikey
    18.09.2015 17:55

    Без защиты от брутофорса бесполезно sakurity.com/otp


    1. lukashin
      18.09.2015 19:21

      Эээ, как это бесполезно? По вашей ссылке, чтобы подобрать одноразовый пароль с вероятностью 50% надо слать 20000 r/s.


      1. Chikey
        21.09.2015 22:06

        3 дня посылая по 10 в секунду или чуть дольше в стелс режиме. 10 дней — любой 6 цифровой отп обходится


  1. M_Muzafarov
    21.09.2015 10:24

    Заголовок про защиту на уровне nginx, на деле же получаем еще большое приложение с зависимостями.

    но они требовали обработку коллбэков. Эти решения мне не понравились и я их отверг.

    И странное следствие из этого:
    И так. Я набросал простое приложение.


    Ну и да, выше заметили, что в данный момент приложение не устойчиво к брутфорсу. Скажем, если у меня не удастся успешно попасть в одноразовый пароль, судя по коду приложения, мне ничто не мешает перебрать 8 цифр и получить emergency.


    1. lukashin
      21.09.2015 13:56

      Вообще не вижу противоречий. Одно дело вносить изменения в код сайта, а другое — написать аж 100-200 строк на flask'e. Готов посмотреть ваше решение на голом nginx или с каким-нибудь модулем.
      Опять же, для безопасности веб-сервисов применяется комплекс мер, и это — одна из мер.


    1. foxmuldercp
      28.09.2015 18:13

      Я себе не представляю сервер, выпушенный в продакшен, на котором нет fail2ban. Вот честно, не представляю. Последние лет 5 я таких серверов не видел.


      1. BOPOHA
        29.09.2015 06:00
        +1

        Последние лет 5 я таких серверов не видел

        fail2ban — парсер логов, с постлогикой. Если проект весомо нагружен посетителями, то access логи могут отсутствовать, либо быть весьма кастомными (структура, размера буфера, etc.), что так же не очень хорошо. Из этого можно сделать несколько выводов относительно ваших слов.

        В общем поделитесь своими правилами fail2ban, или поправьте меня.


        1. lukashin
          29.09.2015 07:15

          Согласен, что fail2ban не особо нужен.
          Лучше ограничить количество запросов с помощью haproxy или nginx.