Bottle-Cork — это лёгкая библиотека аутентификации и авторизации для веб-приложений на Python, построенных на микрофреймворке Bottle. Она даёт небольшому self-hosted приложению то, что иначе пришлось бы кое-как реализовывать самому: учётные записи, ролевые права, подписанные cookie-сессии, регистрацию и сброс пароля. В этом руководстве разбираем, как работает Cork, чем он отличается от других вариантов на Python и как безопасно запустить приложение с аутентификацией на своём сервере.
Что делает Bottle-Cork — кратко
| Возможность | Как реализует Cork |
|---|---|
| Учётные записи | Логин, хеш пароля, e-mail, роль и произвольные данные профиля |
| Авторизация | Именованные роли с целочисленным уровнем; декораторы требуют минимальный уровень |
| Сессии | Подписанные cookie с истечением через Beaker; серверное хранилище сессий не требуется |
| Регистрация | Поток с ожиданием подтверждения и токеном в письме |
| Сброс пароля | Подписанный токен с ограниченным временем жизни, доставляемый по e-mail |
| Хранилище | JSON-файлы, MongoDB или SQLAlchemy |
Как работает Cork
Cork располагается между маршрутизацией Bottle и вашими обработчиками. Каждый защищённый запрос вызывает метод Cork, который проверяет cookie-сессию, определяет текущего пользователя и либо пропускает обработчик, либо прерывает выполнение редиректом на страницу входа. Пользователи, роли и ожидающие регистрации хранятся в бэкенде, выбранном при запуске. Для одного небольшого приложения достаточно JSON; при конкурентной записи переходите на MongoDB или SQLAlchemy.
Роли упорядочены по целочисленному уровню. admin на уровне 100 может всё, что может editor на уровне 50, и больше. Обработчики объявляют минимальный требуемый уровень, поэтому авторизация выражается один раз — на маршруте, а не размазана по бизнес-логике.
Минимальное приложение с аутентификацией
from bottle import Bottle, request, redirect
from cork import Cork
from beaker.middleware import SessionMiddleware
aaa = Cork('conf_dir') # бэкенд: users.json, roles.json, ...
app = Bottle()
@app.post('/login')
def login():
aaa.login(request.forms.get('user'),
request.forms.get('pwd'),
success_redirect='/dashboard',
fail_redirect='/login')
@app.route('/dashboard')
def dashboard():
aaa.require(fail_redirect='/login')
return 'Hello %s' % aaa.current_user.username
@app.route('/admin')
def admin():
aaa.require(role='admin', fail_redirect='/login')
return 'Admin area'
wrapped = SessionMiddleware(app, {'session.type': 'cookie',
'session.encrypt_key': 'CHANGE-ME',
'session.validate_key': True})
Две мысли, которые стоит унести, даже если вы никогда не используете Cork: авторизация должна стоять на маршруте одним вызовом require(), а целостность сессии целиком зависит от секретного ключа подписи — длинного, случайного и не хранящегося в дереве исходников.
Роли и авторизация
Держите число ролей небольшим, а разрывы уровней широкими (например 0 = аноним, 30 = пользователь, 60 = редактор, 100 = админ). Широкие разрывы позволяют позже вставить новый уровень без перенумерации. Никогда не давайте права по имени пользователя — проверяйте уровень роли. Имена меняются, ими прикрываются в тикетах поддержки, и они утекают в логи.
Безопасность паролей и сессий
Cork хранит хеши паролей, а не пароли, и подписывает cookie-сессии. Это базовый уровень, а не финиш. Задайте реальную минимальную длину пароля, ограничьте частоту запросов к маршруту входа против credential stuffing, задайте разумный таймаут сессий и меняйте ключ подписи при его утечке. Отдавайте всё по HTTPS, чтобы cookie нельзя было прочитать в канале, и ставьте флаги Secure и HttpOnly.
Bottle-Cork против других вариантов на Python
| Вариант | Фреймворк | Для чего лучше | Компромисс |
|---|---|---|---|
| Bottle-Cork | Bottle / WSGI | Небольшие self-hosted приложения с ролями без БД | Минимум экосистемы; почту и rate-limit подключаете сами |
| Flask-Login | Flask | Управление сессиями в приложениях Flask | Только сессии; роли и регистрация — на вас |
| Authlib | Любой | Провайдеры и клиенты OAuth2 / OpenID Connect | Тяжелее; избыточно для одного внутреннего приложения |
| Django auth | Django | Полноценные приложения на ORM Django | Придётся принять весь фреймворк |
| Authelia / Keycloak | Отдельный SSO | Защита нескольких сервисов одним входом | Отдельный сервис, который сам нужно защищать |
Если у вас уже больше пары self-hosted сервисов, отдельный провайдер идентичности вроде Keycloak часто лучше в долгую — см. наше руководство по установке Keycloak для SSO и IAM. Для одного приложения на Bottle Cork не мешается под ногами.
Харденинг сервера за вашим входом
Аутентификация не сильнее машины, на которой работает. Идеальная страница входа бесполезна, если порт базы данных открыт в интернет или старая админка отвечает на 8080. Считайте сам хост частью границы аутентификации:
- Файрвол по принципу default-deny. Открывайте только 443 (и SSH — по ключу, желательно на нестандартной конфигурации). Инструменты в традиции Firelet, а сегодня
nftablesилиufw, позволяют явно описать разрешённый трафик и проверять его как набор правил, а не как груду разовых команд. - Fail2ban на логах входа и SSH, чтобы банить источники перебора.
- TLS везде с автопродлением сертификатов; весь HTTP — редиректом на HTTPS.
- Обратный прокси (nginx или Caddy) перед процессом Python, чтобы приложение не смотрело в интернет напрямую, а заголовки и лимиты задавались в одном месте.
- Минимум привилегий: запускайте приложение под непривилегированным пользователем, а файл бэкенда делайте читаемым только этим пользователем.
Первые полчаса на новой машине задают тон всему остальному — наш чек-лист по защите выделенного сервера сразу после выдачи разбирает файрвол, SSH и обновления по порядку.
Какой сервер выбрать для self-hosted приложения
Как только входят реальные пользователи, вам нужны предсказуемые CPU и память, фиксированный IP и полный контроль над файрволом — ничего из этого в полной мере не даёт shared-хостинг. Приватный виртуальный сервер годится для лёгкого приложения; выделенный сервер — верный выбор, когда вы храните реальные данные пользователей, держите базу или нужны гарантированные ресурсы без шумных соседей. Если ограничивает бюджет, недорогой выделенный сервер всё равно даёт изоляцию и контроль файрвола, от которых зависит аутентификация.
Сам Bottle-Cork небольшой — и в этом суть: важна не библиотека, а дисциплина вокруг неё — хешированные учётные данные, ролевая авторизация, подписанные сессии и защищённый хост под ними. Сделайте это правильно — и даже приложение на Bottle в сотню строк можно спокойно выставить в открытый интернет.