Введение
Проводя аудиты процессов разработки ПО, мы часто слышим, что функционал реализован во фреймворке, и это может вызывать вопросы со стороны специалистов по информационной безопасности.
Python, будучи одним из популярных языков программирования, предлагает множество фреймворков, каждый из которых должен быть защищен и иметь встроенные механизмы безопасности либо возможности для встраивания этих механизмов. В этой статье попробуем разобраться, какие возможности действительно предоставляют фреймворки, рассмотрим механизмы безопасности и способы их настройки на примере распространенных фреймворков: Django, FastAPI и Flask.
Все эти фреймворки предоставляют разработчикам мощные инструменты для создания защищённых приложений, но их подходы и реализация отличаются.
1. Безопасность Django
Django — это мощный и надежный веб-фреймворк на Python, который включает в себя широкий спектр механизмов безопасности, способствующих созданию защищенных веб-приложений. Одна из ключевых особенностей Django по сравнению с другими фреймворками — это его встроенные механизмы безопасности, в которых представлен ряд инструментов для защиты от самых распространенных атак, таких как CSRF, XSS, SQL-инъекции и другие.
Встроенные механизмы безопасности
CSRF (Межсайтовая подделка запроса)
Django предотвращает атаки CSRF, используя токены, которые проверяются при каждом выполнении запроса на изменение данных. Токен CSRF гарантирует, что каждый запрос к серверу исходит от доверенного пользователя и с доверенного источника. Django автоматически добавляет токен CSRF в каждую форму и проверяет этот токен при получении POST-запроса.
XSS (Межсайтовый скриптинг)
Django защищает от XSS путем автоматического экранирования всех переменных, выводимых в шаблонах. Это предотвращает выполнение в браузере пользователя вредоносных скриптов, которые могли бы быть вставлены через формы ввода данных.
SQL-инъекции
Django использует ORM для генерации всех SQL-запросов к базе данных. Это изолирует разработчиков от непосредственного написания SQL-кода и защищает от SQL-инъекций, так как все запросы строятся с использованием параметризации и проверяются перед выполнением.
Обработка и хранение паролей
Django по умолчанию использует хеширование и соль для паролей, что делает процесс восстановления оригинального пароля из хеша крайне сложным. Для работы с паролями рекомендуется использовать встроенные классы Django, такие как User и make_password.
Аутентификация и авторизация
Django предлагает мощную систему аутентификации и авторизации, которая позволяет легко управлять пользователями, группами, правами доступа и более тонко настраивать доступ к ресурсам. Django предоставляет встроенные средства для аутентификации пользователей таких классов, как User и Authentication Middleware.
Clickjacking
Защита от clickjacking в Django осуществляется через механизм X-Frame-Options, который позволяет сайтам указывать на обстоятельства для загрузки контента во фрейме. Это предотвращает атаки, при которых злоумышленник может ввести пользователя в заблуждение, заставив его кликнуть на скрытый фрейм.
2. Настройка параметров безопасности Django
Настройка параметров безопасности в Django осуществляется через файл settings.py, который является центральным местом для конфигурации приложения. В этом файле можно настроить различные параметры, которые повлияют на безопасность вашего приложения.
Основные параметры безопасности
SECRET_KEY
Значение по умолчанию: Не задан по умолчанию, должен быть уникальным.
Назначение: Используется для криптографической подписи, важен для безопасности сессий и данных, связанных с cookies.
Примечание: Никогда не размещайте SECRET_KEY в публично доступных источниках.
DEBUG
Значение по умолчанию: True
Назначение: При включении выводит подробную информацию об ошибках, что может быть опасно на продакшн сервере.
Примечание: Всегда устанавливайте DEBUG = False на продакшн серверах.
ALLOWED_HOSTS
Значение по умолчанию: []
Назначение: Определяет список строк, представляющих имена хостов/доменов, которым разрешено обслуживать этот сайт.
Примечание: Настройте это значение в соответствии с доменами, на которых должно работать ваше приложение.
SECURE_BROWSER_XSS_FILTER
Значение по умолчанию: False
Назначение: Включает XSS фильтр в браузере пользователя.
Примечание: Рекомендуется устанавливать True для защиты от XSS атак.
X_FRAME_OPTIONS
Значение по умолчанию: DENY
Назначение: Управляет загрузкой сайта внутри тега <frame>, <iframe> , <object>.
Примечание: DENY блокирует все попытки загрузки страниц во фреймы, что помогает предотвратить clickjacking.
SECURE_SSL_REDIRECT
Значение по умолчанию: False
Назначение: Перенаправляет все HTTP запросы на HTTPS.
Примечание: Включите в продакшн, если ваш сайт работает полностью через HTTPS.
CSRF_COOKIE_SECURE
Значение по умолчанию: False
Назначение: Указывает, что cookie CSRF должен передаваться только по HTTPS.
Примечание: Включите, если ваш сайт использует HTTPS.
SESSION_COOKIE_SECURE
Значение по умолчанию: False
Назначение: Указывает, что cookie сессии должны передаваться только по HTTPS.
Примечание: Аналогично CSRF_COOKIE_SECURE, включите для HTTPS сайтов.
Пример настроенного файла конфигурации
# settings.py
SECRET_KEY = 'your_secret_key_here'
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.ru', 'www.yourdomain.ru']
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'
SECURE_SSL_REDIRECT = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
# Дополнительные настройки безопасности
SECURE_HSTS_SECONDS = 31536000 # Включение HSTS с длительностью один год
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
3. Безопасность FastAPI
FastAPI — это современный и высокопроизводительный фреймворк для создания API. Он не имеет встроенной системы безопасности в традиционном понимании. Вместо этого он предоставляет модуль fastapi.security, который включает в себя ряд классов для аутентификации и работы с API ключами.
Встроенные механизмы безопасности
Аутентификация и авторизация
FastAPI поддерживает несколько способов аутентификации, включая:
OAuth2: С использованием OAuth2PasswordBearer, фреймворк может управлять токенами доступа, что часто применяется в современных API.
API ключи: Механизмы, такие как APIKeyHeader, APIKeyQuery и APIKeyCookie, позволяют использовать API ключи для простой аутентификации запросов.
Обработка и хранение паролей
FastAPI предлагает интеграцию с библиотеками, такими как passlib и bcrypt, для безопасного хеширования и проверки паролей. Эти библиотеки помогают разработчикам легко реализовать надежное хеширование паролей и их последующую проверку. FastAPI сам по себе не имеет встроенных инструментов для работы с паролями, но легко интегрируется с внешними библиотеками, предоставляющими такие возможности.
Защита от CSRF и XSS
CSRF: Поскольку FastAPI обычно используется для создания API с токенами аутентификации, CSRF не является такой значительной угрозой, как в традиционных веб-формах. Тем не менее, для сценариев, где используются cookie, рекомендуется применять сторонние решения для добавления токенов CSRF.
XSS: FastAPI автоматически не обрабатывает XSS, так как это относится к контенту, который генерируется на стороне клиента. Разработчики должны убедиться, что все пользовательские данные, выводимые в веб-приложениях, должным образом очищаются и экранируются.
Защита от SQL-инъекций
Использование ORM, таких как SQLAlchemy, предоставляет защиту от SQL-инъекций. FastAPI легко интегрируется с такими ORM, гарантируя, что все запросы к базе данных строго параметризованы — это предотвращает внедрение вредоносного кода.
Clickjacking
Для защиты от clickjacking разработчики могут использовать заголовки HTTP, такие как X-Frame-Options, для контроля загрузки страниц во фреймах. FastAPI позволяет легко добавлять заголовки через ответы API или средствами Starlette middleware.
4. Настройка параметров безопасности FastAPI
FastAPI сам по себе не имеет специализированного файла конфигурации безопасности. Вместо этого параметры безопасности и конфигурации определяются напрямую в коде приложения.
Основные механизмы безопасности
Аутентификация OAuth2:
Назначение: Используется класс OAuth2PasswordBearer для создания механизма получения токенов.
Примечание: Обеспечивает безопасность API путём проверки токенов доступа перед обработкой запросов пользователя.
Пример:
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
return {"token": token}
API ключи:
Назначение: Использование классов APIKeyHeader, APIKeyQuery, и APIKeyCookie для обработки API ключей.
Примечание: Проверка API ключей для доступа к определенным маршрутам или функциям API.
Пример:
from fastapi import FastAPI, Security
from fastapi.security.api_key import APIKeyHeader, APIKey
app = FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")
async def get_api_key(api_key_header: str = Security(api_key_header)):
if api_key_header == "secret-key":
return "Authorized"
else:
return "Unauthorized"
@app.get("/secure-data")
async def secure_data(authorization: str = Security(get_api_key)):
return {"status": authorization}
HTTP Basic Auth:
Назначение: Использование класса HTTPBasic для базовой аутентификации.
Примечание: Простая аутентификация пользователя с помощью имени пользователя и пароля.
Пример:
import secrets
from fastapi import FastAPI, Depends
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.exceptions import HTTPException
app = FastAPI()
security = HTTPBasic()
def check_credentials(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = secrets.compare_digest(credentials.username, "user")
correct_password = secrets.compare_digest(credentials.password, "password")
if not (correct_username and correct_password):
raise HTTPException(status_code=401, detail="Incorrect email or password")
return credentials
@app.get("/secure-area")
def secure_area(credentials: HTTPBasicCredentials = Depends(check_credentials)):
return {"message": "Secure area accessed", "user": credentials.username}
Пример настроенного файла конфигурации
import secrets
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, APIKeyHeader, HTTPBasic, HTTPBasicCredentials
from jose import jwt # Добавлен для обработки JWT токенов
app = FastAPI()
# Настройки безопасности
security = HTTPBasic()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
api_key_header = APIKeyHeader(name="X-API-Key")
# Функции проверки аутентификации
def check_credentials(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = secrets.compare_digest(credentials.username, "user")
correct_password = secrets.compare_digest(credentials.password, "password")
if not (correct_username and correct_password):
raise HTTPException(status_code=401, detail="Incorrect email or password")
return credentials
def get_api_key(api_key: str = Depends(api_key_header)):
if api_key == "correct_key":
return api_key
else:
raise HTTPException(status_code=401, detail="Invalid API key")
# Маршруты
@app.post("/token")
async def login():
# Предположим, что функция возвращает токен JWT после проверки учетных данных (опущено для простоты)
return {"access_token": "your_token"}
@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
# Возвращаем данные о пользователе,использующем токен
return {"token": token}
@app.get("/secure-area")
def secure_area(credentials: HTTPBasicCredentials = Depends(check_credentials)):
# Доступ к защищенной области с использованием HTTP Basic Auth
return {"message": "Secure area accessed", "user": credentials.username}
@app.get("/secure-data")
async def secure_data(api_key: str = Depends(get_api_key)):
# Доступ к защищенным данным с использованием API ключа
return {"message": "Access granted", "api_key": api_key}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
5. Безопасность Flask
Flask — это легковесный веб-фреймворк для Python, который широко используется для создания веб-приложений и API. Благодаря своей гибкости и минималистичной структуре Flask предоставляет разработчикам основу для реализации множества функций безопасности, но многие аспекты безопасности требуют ручной настройки или интеграции с внешними библиотеками.
Встроенные механизмы безопасности
Защита от CSRF (Межсайтовой подделки запроса)
Flask-WTF, расширение для Flask, обеспечивает защиту от CSRF. Это расширение автоматически добавляет токены CSRF к формам и проверяет эти токены при получении запросов, что помогает предотвратить несанкционированные действия от имени аутентифицированных пользователей.
Защита от XSS (Межсайтового скриптинга)
Для борьбы с XSS, Flask и его шаблонизатор Jinja2 автоматически экранируют все выводы переменных в шаблонах, если только не указано иное. Это предотвращает исполнение нежелательных скриптов, которые могли бы быть вставлены в содержимое страниц через пользовательский ввод.
Защита от SQL-инъекций
Использование ORM, таких как SQLAlchemy, предотвращает SQL-инъекции, так как запросы к базе данных формируются без прямой передачи параметров от пользователя, что исключает возможность выполнения вредоносного кода через входные данные.
Аутентификация и авторизация
Flask-Login — это инструмент для управления пользовательскими сессиями, который упрощает процесс аутентификации. Он помогает разработчикам контролировать доступ к определенным разделам приложения, требуя от пользователей входа в систему.
Защита от Clickjacking
Для защиты от кликджекинга можно использовать заголовок X-Frame-Options. Flask-Talisman, еще одно расширение, которое позволяет легко управлять заголовками безопасности, включая CSP (Content Security Policy) и помогает в борьбе с XSS и другими векторами атак.
6. Настройка параметров безопасности Flask
Во Flask параметры безопасности обычно задаются в файле конфигурации config.py. Flask не имеет встроенного файла конфигурации по умолчанию, но предлагает гибкую систему настройки.
Основные параметры безопасности
Ниже перечислены ключевые параметры безопасности, которые можно настроить в Flask:
SECRET_KEY
Значение по умолчанию: Не задан по умолчанию, должен быть уникальным.
Назначение: Используется для подписывания сессионных cookie и других безопасных операций.
Примечание: Ключ должен быть защищен и не раскрываться.
SESSION_COOKIE_SECURE
Значение по умолчанию: False
Назначение: Указывает браузеру использовать cookies только через HTTPS.
Примечание: Включайте, только если вы используете HTTPS.
SESSION_COOKIE_HTTPONLY
Значение по умолчанию: True
Назначение: Предотвращает доступ JavaScript к cookies.
Примечание: Помогает противостоять XSS атакам.
PERMANENT_SESSION_LIFETIME
Значение по умолчанию: 31 день
Назначение: Устанавливает продолжительность жизни постоянной сессии.
Примечание: Значение задается как объект timedelta.
REMEMBER_COOKIE_DURATION
Значение по умолчанию: 365 дней
Назначение: Устанавливает, как долго cookie будет сохранять информацию о входе в систему.
Примечание: При использовании Flask-Login.
Пример настроенного файла конфигурации
from datetime import timedelta
from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key_here'
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
app.config['REMEMBER_COOKIE_DURATION'] = timedelta(days=14)
@app.route('/')
def index():
return "Welcome to the Flask app!"
if __name__ == "__main__":
app.run(ssl_context='adhoc')
Заключение
Фреймворки Python предоставляют обширные возможности для обеспечения безопасности приложений. Независимо от того, используете ли вы Django, FastAPI или Flask, каждый из этих фреймворков обладает набором инструментов, способствующих защите от самых распространенных угроз встроенными или интегрируемыми способами. Однако важно понимать, что ни один инструмент или фреймворк не может обеспечить полную безопасность сам по себе. Применение лучших практик и использование проверенных библиотек играют ключевую роль в повышении безопасности ваших приложений. Резюмируя, можно сказать, что безопасность приложений зависит не только от выбранного фреймворка, но и от вашего внимания к деталям безопасности на каждом этапе разработки.
Автор: Артем Порфирьев, старший инженер по безопасности приложений УЦСБ