Результати аудиту безпеки: чому мені було соромно
Нещодавно я провів аудит безпеки всіх своїх власних проєктів. Це включає мій FastAPI backend, Telegram-ботів, PWA та застосунки Streamlit.
Я думав, що мій код у безпеці, бо я був обережним. Я помилявся.
Я ділюся цими реальними багами з продакшену, щоб допомогти вам їх уникнути. Це не теоретичні чек-листи. Це помилки, які я справді припустився.
The Conditional Authentication Trap Я написав код, який перевіряв наявність API secret перед його верифікацією. Якщо змінна оточення була відсутня, перевірка просто пропускалася. Це означало, що весь мій API був відкритим для публіки. Rule: Якщо секрет відсутній, видавайте жорстку помилку 500. Ніколи не пропускайте автентифікацію.
The Git History Leak Одного разу я захардкодив API key для швидкого тесту. Згодом я переніс його у файл .env і думав, що проблему вирішено. Але Git пам'ятає все. Будь-хто може знайти цей ключ у моїй історії комітів. Rule: Якщо ви закомітили ключ, вважайте, що його вкрали. Негайно змініть його (rotate). Використовуйте git-filter-repo, щоб очистити свою історію.
The Debug Endpoint Leak Я залишив ендпоінт /debug/config у продакшені, щоб полегшити пошук несправностей. Він відкривав мої URL-адреси баз даних та налаштування оточення. Rule: Видаляйте всі debug-ендпоінти перед розгортанням. Замість цього використовуйте логи.
Leaking System Info via Errors Я використовував
str(e)у своїх відповідях на помилки. Це надсилало помилки бази даних та шляхи до файлів безпосередньо користувачеві. Зловмисники використовують це, щоб виявити структуру вашої інфраструктури. Rule: Логуйте детальну помилку для себе. Надсилайте клієнту загальне повідомлення "Internal Server Error".The XSS Risk in Frontend Я використовував
innerHTMLдля рендерингу контенту користувачів. Це дозволяло скриптам виконуватися в браузерах інших користувачів. Rule: Завжди екрануйте HTML. Ставтеся доinnerHTMLяк до способу виконання довільного коду.Missing Rate Limits У мене були ендпоінти, які викликали дорогі моделі ШІ без будь-яких обмежень. Один цикл або вкрадений ключ міг коштувати мені сотні доларів. Rule: Автентифікація зупиняє неавторизованих користувачів. Rate limiting зупиняє авторизованих користувачів від зловживання вашою системою.
Permissive CORS Policy Я використовував
allow_origins=["*"]у продакшені. Це дозволяє будь-якому сайту робити запити до вашого API. Rule: Дозволяйте лише ваш конкретний домен фронтенду.Витік тимчасових файлів Якщо мій код аварійно завершував роботу під час обробки файлу, тимчасовий файл залишався на диску назавжди. Це марнує місце та призводить до витоку конфіденційних даних. Правило: Використовуйте блоки try-finally, щоб гарантувати видалення файлів навіть у разі виникнення помилки.
Мій новий обов'язковий чекліст:
Перед написанням коду: • Створіть .gitignore • Створіть .env.example
Для кожного ендпоінту: • Додайте автентифікацію • Використовуйте загальні повідомлення про помилки • Додайте обмеження частоти запитів (rate limits) для ресурсомістких завдань
Перед комітом: • Перевірте diff на наявність секретних даних
Перед розгортанням: • Проводьте аудит безпеки ваших залежностей
Проблеми з безпекою не виникають випадково. Вони з'являються через коментарі "TODO" та "тимчасові" виправлення, які залишаються в продакшені назавжди.
Виправляти баг — нудно. Усувати наслідки зламу — дорого.