Как обрабатывать CSRF для iFrame в Django с несколькими белыми метками без использования белого списка доменов?

Вопросы и ответы

Я создаю решение под собственным брендом, используя Django, где мои клиенты могут встроить формы из моего приложения на свои сайты с помощью iFrame. Однако у меня возникла проблема с защитой от CSRF, когда форма отправляется с этих внешних сайтов, в результате чего возникает ошибка 403 Forbidden из-за «Ошибка проверки CSRF».

Моя настройка:

**Фреймворк: ** Django 4.x с включенной защитой CSRF.
Сценарий использования: Несколько клиентов встраивают нашу форму (отрендеренную с помощью шаблонов Django) на свои сайты. Пользователи отправляют форму с этих внешних доменов.

Проблема: Поскольку токен CSRF зависит от файлов cookies и кросс-доменных политик, токен CSRF не включается в отправку формы, что приводит к сбоям проверки.

Ограничения:

Без API-вызовов: Форма рендерится на стороне сервера с использованием шаблонов Django, и мы не используем фронтенд-фреймворк, такой как React или Vue, поэтому решения на основе API не подходят.
Динамическое встраивание: Нет фиксированного числа клиентских сайтов, которые могут использовать форму, поэтому поддержание белого списка доменов для исключения CSRF не является масштабируемым.
Безопасность: Я все еще хочу сохранить защиту от CSRF в целях безопасности.

Что я пробовал:

Отключение промежуточного ПО CSRF: Работает, но это компрометирует безопасность, так что это не жизнеспособное долгосрочное решение.
Установка CSRF_COOKIE_SAMESITE в None: Не имеет эффекта из-за ограничений кросс-домена.
Разрешение CORS: Не решило проблему, поскольку не применяется к валидации токена CSRF.
Задача:
Мне нужно масштабируемое решение, которое позволит формам, встроенным через iFrame с любого клиентского сайта, безопасно проходить проверку CSRF. Поскольку мы не можем предсказать, какие домены будут использовать форму, поддерживать список разрешенных доменов непрактично. Решение должно обрабатывать CSRF безопасным способом без необходимости вручную вносить каждую доменную в белый список.

Вопросы:

  1. Есть ли способ динамически передавать токены CSRF или иным образом обрабатывать защиту CSRF для iFrame в Django?

  2. Как мы можем безопасно обрабатывать CSRF для неограниченного числа клиентских сайтов без поддержания белого списка доменов?

  3. Существуют ли конфигурации Django или решения промежуточного ПО, предназначенные для такого типа сценария использования?
    Любые идеи или рекомендации будут очень полезны!

Ответ

Вопросы о защите от CSRF (Cross-Site Request Forgery) в Django, особенно при работе с iFrame и несколькими клиентскими сайтами, могут быть достаточно сложными. В вашем случае, когда вы хотите, чтобы ваши формы удобно встраивались на любые внешние сайты, и при этом соблюдалась безопасность, есть несколько возможных решений.

Подход к Решению Проблемы CSRF

  1. Встраивание CSRF-токена в форму:

    • Когда ваша форма создается на сервере, вы можете динамически добавлять CSRF-токен к форме, чтобы он был включен в отправляемый запрос.
    • Используйте встроенные теги Django для добавления CSRF-токена в вашу HTML-форму:
      <form method="post" action="{% url 'your_view' %}">
       {% csrf_token %}
       <!-- остальные поля формы -->
       <input type="submit" value="Отправить">
      </form>
  2. Использование PostMessage для передачи CSRF-токена:

    • Если ваш iFrame загружается с другого домена, вы не можете получить доступ к cookies и заголовкам из-за политик CORS. Поэтому можно использовать механизм postMessage для передачи CSRF-токена из родительского окна в iFrame. Основные шаги:
      • Родительский сайт (внешний сайт) должен отправить сообщение с CSRF-токеном в iFrame с помощью JavaScript.
      • В iFrame вы будете слушать это сообщение и сохранять токен, когда он будет доступен. Например:
        window.addEventListener('message', function(event) {
        // Проверьте источник сообщения, чтобы убедиться, что это доверенный источник
        if (event.origin === "https://trusted-domain.com") {
           document.getElementById("csrf_token").value = event.data.csrf_token;
        }
        });
      • Так как CSRF-токен устанавливается на вашем сайте, формирование и передача должны происходить в безопасном контексте.
  3. Создание API-эндпоинта для получения CSRF-токена:

    • Вы можете создать специальный эндпоинт, который позволяет запрашивать CSRF-токен с вашего сервера. Этот эндпоинт должен быть защищен, например, через базовую аутентификацию или другой метод проверки подлинности, который гарантирует, что только надежные источники могут запрашивать токен.
    • Например:

      from django.views.decorators.csrf import ensure_csrf_cookie
      from django.http import JsonResponse
      
      @ensure_csrf_cookie
      def csrf_token_view(request):
       return JsonResponse({'csrf_token': get_token(request)})
  4. Использование временных токенов:
    • Альтернативный подход — использовать временные и одноразовые токены, которые могут быть сгенерированы на сервере для каждой сессии. Эти токены можно передавать вместе с формой и проверять на серверной стороне.

Заключение

Изложенные выше подходы позволяют сохранить защиту от CSRF для форм, встроенных в iFrames, без необходимости поддерживать список разрешенных доменов. В зависимости от конкретных обстоятельств и уровня конфиденциальности данных, которые обрабатываются, вам может подойти один из предложенных методов или их комбинация. Обязательно примите все меры предосторожности при проверке источника данных и передаче токенов, чтобы гарантировать безопасность вашей системы.

Оцените материал
Добавить комментарий

Капча загружается...