Как вы можете удалить соединение HttpRequest в Django, когда TLS/SSL не используется?

Я пишу метод представления Django 1.3, который требует использования TLS/SSL. Я хочу полностью удалить соединение, если HttpRequest получен без использования TLS/SSL и НЕ возвращает какой-либо ответ. Это по соображениям безопасности.

В настоящее время я возвращаю ответ так:

def some_view(request):
    if not request.is_secure():
        return HttpResponse(status=426)
    ...

Однако возврат 426 - Upgrade Required создает несколько проблем:

  • Это часть предлагаемого стандарта с мая 2000 года (RFC 2817) и не является официальным стандартом HTTP.
  • HttpResponse открыт для атаки "человек-в-середине" (MITM). Как указано в комментариях здесь, если сервер возвращает любой тип ответа клиенту без установления соединения TLS/SSL, которое сначала устанавливается, MITM может захватить ответ, изменить его перенаправить в другое место и доставить вредоносный ответ повторно на клиента.

Если перенаправление сервера из URI HTTP в URI HTTPS открыто для той же атаки MITM, как указано выше.

Итак, как вы можете полностью удалить соединение внутри метода представления Django 1.3 без возврата какого-либо типа HttpResponse?

Ответ 1

Как я уже говорил в этом ответе, я вообще против использования автоматических перенаправлений от http:// до https:// по причинам, которые вы упоминаете, Я бы не рекомендовал прибегать только к перенаправлению mod_rewrite -style для обеспечения безопасности сайта.

Однако, в вашем случае, к моменту поступления запроса на сервер, это слишком поздно. Если есть MITM, он совершил свою атаку (или ее часть), прежде чем вы получите запрос.

Лучшее, что вы можете сделать к тому времени, - ответить без какого-либо полезного контента. В этом случае может потребоваться перенаправление (с использованием 301 или 302 и заголовка Location). Тем не менее, это может скрыть проблемы, если пользователь (или даже вы как разработчик) игнорирует предупреждения (в этом случае браузер будет следовать перенаправлению и повторить запрос почти прозрачно).

Поэтому я просто предлагаю вернуть статус 404:

  • http://yoursite/ и https://yoursite/ являются фактически двумя разными сайтами. Нет причин ожидать отображения 1:1 всех ресурсов из пространств URI от одного к другому (точно так же, как вы могли бы иметь совершенно другую иерархию для ftp://yoursite/).
  • Что еще более важно, это проблема, с которой следует обращаться вверх по течению: ссылка, которая привела пользователя к этому ресурсу с помощью http://, должна считаться нарушенной. Не заставляйте его работать автоматически. Наличие статуса 404 для ресурса, который не должен быть там, прекрасен. Кроме того, возврат сообщения об ошибке при наличии ошибки является хорошим: он заставит вас (или, по крайней мере, напомнить вам), как разработчика, что вам нужно исправить страницу/форму/ссылку, которые привели к этой проблеме.

Отключение соединения - это просто бонус, если вы можете сделать это с помощью этой структуры: это будет действительно полезно, если оно может быть отправлено асинхронно сервером (до того, как клиент завершит отправку запроса), если браузер может прочитайте его асинхронно (в этом случае он должен немедленно прекратить отправку при возникновении ошибки), и если атакующий MITM является пассивным (активный MITM может остановить ответ, чтобы вернуться через клиент и убедиться, что клиент отправляет весь запрос, потребляя он имеет свой собственный "прокси", независимо от того, отключил ли сервер соединение). Эти условия могут произойти, но исправление проблемы в источнике все равно лучше.

Ответ 2

Если вы используете Nginx в качестве своего прокси-сервера, вы можете использовать другой нестандартный код статуса 444 HTTP, который закрывает соединение без отправки каких-либо заголовков. http://wiki.nginx.org/HttpRewriteModule#return Это потребует, чтобы Nginx знал достаточно о том, какие URL-адреса отказывают в HTTP.