Статья по безопасности Django (Django Security Cheat Sheet)
Введение
Django — мощный веб-фреймворк на Python; в нём уже есть средства защиты от типичных уязвимостей, которые можно использовать «из коробки». В этой статье перечислены действия и советы по разработке более безопасных приложений на Django: она охватывает распространённые риски и помогает усилить защиту. У каждого пункта — краткое пояснение и примеры кода в контексте Django.
Многие настройки Django по умолчанию ориентированы на безопасность, при этом компоненты гибко переопределяются под сложные сценарии. Неопытная настройка может ослабить защиту. Статья перечисляет типичные такие случаи.
Общие рекомендации
- Регулярно обновляйте Django и зависимости проекта, чтобы получать исправления уязвимостей.
- В продакшене приложение не должно работать в режиме
DEBUG. Никогда не используйтеDEBUG = Trueв бою. - Подключайте пакеты вроде
django_ratelimitилиdjango-axesдля ограничения частоты запросов и защиты от перебора паролей.
Аутентификация
- Для входа, выхода, смены пароля и т.п. используйте приложение
django.contrib.authи его формы/представления. Подключите модуль и зависимостиdjango.contrib.contenttypesиdjango.contrib.sessionsвINSTALLED_APPSвsettings.py.
INSTALLED_APPS = [
# ...
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
# ...
]- Декоратор
@login_requiredограничивает доступ к представлению только аутентифицированным пользователям. Ниже — типичные варианты.
from django.contrib.auth.decorators import login_required
# Неаутентифицированный пользователь перенаправляется на страницу входа по умолчанию.
@login_required
def my_view(request):
# логика представления
pass
# Перенаправление на свой URL входа.
@login_required(login_url='/login-page/')
def my_view(request):
# логика представления
pass- Задайте политику паролей через валидаторы: настройте
AUTH_PASSWORD_VALIDATORSвsettings.pyпод требования приложения.
AUTH_PASSWORD_VALIDATORS = [
{
# Сходство пароля с атрибутами пользователя.
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
'OPTIONS': {
'user_attributes': ('username', 'email', 'first_name', 'last_name'),
'max_similarity': 0.7,
}
},
{
# Минимальная длина пароля.
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 8,
}
},
{
# Проверка по списку распространённых паролей.
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
# Запрет полностью числового пароля.
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
}
]- Для хеширования пароля в виде открытого текста используйте утилиту
make_password.
from django.contrib.auth.hashers import make_password
# ...
hashed_pwd = make_password('plaintext_password')- Проверку открытого пароля на соответствие хешу выполняйте через
check_password.
from django.contrib.auth.hashers import check_password
# ...
plain_pwd = 'plaintext_password'
hashed_pwd = 'hashed_password_from_database'
if check_password(plain_pwd, hashed_pwd):
print("The password is correct.")
else:
print("The password is incorrect.")Управление ключами
Параметр SECRET_KEY в settings.py используется для криптографической подписи и должен храниться в секрете. Рекомендации:
- Генерируйте ключ длиной не менее 50 символов из букв, цифр и символов.
- Используйте криптостойкий генератор, например
get_random_secret_key()в Django. - Не зашивайте
SECRET_KEYв репозиторий. Храните значение в переменных окружения или в менеджере секретов.
import os
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')- Планируйте ротацию ключа с учётом того, что это инвалидирует сессии, токены сброса пароля и т.д. При компрометации ключ смените немедленно.
Заголовки HTTP
Включите django.middleware.security.SecurityMiddleware в списке MIDDLEWARE в settings.py, чтобы добавлять к ответам заголовки, связанные с безопасностью. Среди прочего настраиваются:
SECURE_CONTENT_TYPE_NOSNIFF: установитеTrue, чтобы включитьX-Content-Type-Options: nosniffи снизить риск подмены MIME.SECURE_HSTS_SECONDS: задаёт политику HSTS (доступ к сайту только по HTTPS).
Подключите django.middleware.clickjacking.XFrameOptionsMiddleware в MIDDLEWARE (после SecurityMiddleware — порядок важен) для параметров вроде:
X_FRAME_OPTIONS: значениеDENYилиSAMEORIGINдобавляет заголовокX-Frame-Optionsко всем ответам и помогает против clickjacking.
Content Security Policy (CSP)
Встроенной поддержки CSP в Django по умолчанию нет. Реализуйте политику через сторонние библиотеки (например, django-csp) или через заголовки HTTP.
Подробнее:
Файлы cookie
SESSION_COOKIE_SECURE = Trueвsettings.py— передавать cookie сессии только по HTTPS.CSRF_COOKIE_SECURE = True— то же для CSRF-cookie.- При установке своих cookie через
HttpResponse.set_cookie()задавайтеsecure=True.
response = HttpResponse("Some response")
response.set_cookie('my_cookie', 'cookie_value', secure=True)Межсайтовая подделка запроса (CSRF)
- Включите
django.middleware.csrf.CsrfViewMiddlewareвMIDDLEWAREвsettings.py. - В формах используйте тег шаблона
{% csrf_token %}, как в примере ниже.
<form method="post">
{% csrf_token %}
<!-- поля формы -->
</form>- Для AJAX сначала получите CSRF-токен и передайте его в запросе.
- Дополнительные меры описаны в документации Django по защите от CSRF.
См. также OWASP: предотвращение CSRF.
Межсайтовый скриптинг (XSS)
Рекомендации этого раздела дополняют общие меры против XSS.
- Используйте встроенный шаблонизатор Django. Автоэкранирование HTML описано в документации.
- По возможности не отключайте экранирование фильтром
safeи функциейmark_safe. Если без этого нельзя, убедитесь, что данные из доверенного источника; к пользовательскому вводу относитесь особенно осторожно. - Для передачи данных в JavaScript из шаблонов используйте фильтр
json_script. - Подробнее — раздел Django про защиту от XSS.
См. OWASP: предотвращение XSS.
HTTPS
- Убедитесь, что в
MIDDLEWAREестьdjango.middleware.security.SecurityMiddleware. SECURE_SSL_REDIRECT = Trueвsettings.pyперенаправляет HTTP на HTTPS (301).- За прокси или балансировщиком настройте
SECURE_PROXY_SSL_HEADER, чтобы Django корректно определял схему исходного запроса. См. документацию.
URL панели администратора
Имеет смысл изменить стандартный путь к админке (example.com/admin/), чтобы усложнить автоматизированные атаки. В корневом urls.py проекта измените элемент в urlpatterns, ведущий на admin.site.urls, на путь, отличный от admin/.
Встроенная команда Django check --deploy
Для проверок перед выкладкой используйте check --deploy. Пример вывода:
$ ./manage.py check --deploy
System check identified some issues:
WARNINGS:
?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served only over SSL, you may want to consider setting a value and enabling HTTP Strict Transport Security. Be sure to read the documentation first; enabling HSTS carelessly can cause serious, irreversible problems.
?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over both SSL and non-SSL connections, you may want to either set this setting True or configure a load balancer or reverse-proxy server to redirect all connections to HTTPS.
?: (security.W009) Your SECRET_KEY has less than 50 characters, less than 5 unique characters, or it's prefixed with 'django-insecure-' indicating that it was generated automatically by Django. Please generate a long and random value, otherwise many of Django's security-critical features will be vulnerable to attack.
?: (security.W012) SESSION_COOKIE_SECURE is not set to True. Using a secure-only session cookie makes it more difficult for network traffic sniffers to hijack user sessions.
?: (security.W016) You have 'django.middleware.csrf.CsrfViewMiddleware' in your MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. Using a secure-only CSRF cookie makes it more difficult for network traffic sniffers to steal the CSRF token.
?: (security.W018) You should not have DEBUG set to True in deployment.
?: (security.W020) ALLOWED_HOSTS must not be empty in deployment.
System check identified 7 issues (0 silenced).Устранение предупреждений этой команды — практичный шаг к более жёсткой конфигурации в продакшене.
Ссылки
Дополнительная документация:
© Перевод на русский язык. Оригинальные материалы: OWASP Cheat Sheet Series.
Этот проект использует материалы OWASP, распространяемые по лицензии CC BY-SA 4.0.