Результаты аудита безопасности: почему мне было стыдно
Недавно я провел аудит безопасности всех своих личных проектов. Сюда входят мой бэкенд на FastAPI, Telegram-боты, PWA и приложения на Streamlit.
Я думал, что мой код в безопасности, потому что я был осторожен. Я ошибался.
Я делюсь этими реальными багами из продакшена, чтобы помочь вам их избежать. Это не теоретические чек-листы. Это ошибки, которые я совершил на самом деле.
Ловушка условной аутентификации Я написал код, который сначала проверял наличие API-секрета, а только потом его верифицировал. Если переменная окружения отсутствовала, проверка просто пропускалась. Это означало, что весь мой API был открыт для всех. Правило: Если секрет отсутствует, выдавайте ошибку 500. Никогда не пропускайте аутентификацию.
Утечка через историю Git Однажды я захардкодил API-ключ для быстрого теста. Позже я перенес его в файл
.envи подумал, что проблема решена. Но Git помнит всё. Любой может найти этот ключ в истории моих коммитов. Правило: Если вы закоммитили ключ, считайте, что его украли. Немедленно проведите ротацию. Используйтеgit-filter-repo, чтобы очистить историю.Утечка отладочного эндпоинта Я оставил эндпоинт
/debug/configв продакшене, чтобы было проще проводить отладку. Он раскрывал URL-адреса моих баз данных и настройки окружения. Правило: Удаляйте все отладочные эндпоинты перед деплоем. Вместо этого используйте логи.Утечка системной информации через ошибки Я использовал
str(e)в ответах об ошибках. Это отправляло ошибки базы данных и пути к файлам напрямую пользователю. Злоумышленники используют это для построения карты вашей инфраструктуры. Правило: Логируйте подробную ошибку для себя. Отправляйте клиенту стандартное сообщение "Internal Server Error".Риск XSS на фронтенде Я использовал
innerHTMLдля рендеринга пользовательского контента. Это позволяло скриптам запускаться в браузерах других пользователей. Правило: Всегда экранируйте HTML. Относитесь кinnerHTMLкак к способу выполнения произвольного кода.Отсутствие ограничений частоты запросов (Rate Limits) У меня были эндпоинты, которые вызывали дорогие модели ИИ без каких-либо ограничений. Один цикл или украденный ключ могли стоить мне сотни долларов. Правило: Аутентификация останавливает неавторизованных пользователей. Rate limiting останавливает авторизованных пользователей от злоупотребления вашей системой.
Слишком разрешительная политика CORS В продакшене я использовал
allow_origins=["*"]. Это позволяет любому сайту отправлять запросы к вашему API. Правило: Разрешайте доступ только вашему конкретному домену фронтенда.Утечка временных файлов Если мой код аварийно завершался во время обработки файла, временный файл оставался на диске навсегда. Это расходует место и приводит к утечке конфиденциальных данных. Правило: Используйте блоки try-finally, чтобы гарантировать удаление файлов даже в случае возникновения ошибки.
Мой новый обязательный чек-лист:
Перед написанием кода: • Создайте .gitignore • Создайте .env.example
Для каждого эндпоинта: • Добавьте аутентификацию • Используйте общие сообщения об ошибках • Добавьте ограничения частоты запросов для ресурсоемких задач
Перед коммитом: • Проверьте diff на наличие секретов
Перед развертыванием: • Проведите аудит безопасности ваших зависимостей
Проблемы с безопасностью не возникают случайно. Они появляются из-за комментариев «TODO» и «временных» исправлений, которые навсегда остаются в продакшене.
Исправлять баги — скучно. Исправлять утечку данных — дорого.