3

I'm writing a Django 1.3 view method which requires TLS/SSL to be used. I want to entirely drop the connection if an HttpRequest is received without using TLS/SSL and NOT return any kind of response. This is for security reasons.

Currently I am returning a response like so:

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

However, returning 426 - Upgrade Required poses a couple of problems:

  1. It's part of a proposed standard from May 2000 (RFC 2817), and is not an official HTTP standard.
  2. The HttpResponse is open to a man-in-the-middle (MITM) attack. As mentioned in the comments here, if the server returns any type of response to the client without a TLS/SSL connection first being established, a MITM could hijack the response, alter it to re-direct elsewhere, and deliver the malicious re-direct response to the client.

Having the server re-direct from a HTTP URI to a HTTPS URI is open to the same MITM attack as noted above.

So, how can you entirely drop a connection inside a Django 1.3 view method without returning any type of HttpResponse?

Community
  • 1
  • 1
Dave
  • 12,408
  • 12
  • 64
  • 67
  • 2
    Many "proposed standards" in the IETF terminology could be considered as some form of actual standard in practice. After all, RFC 2616 (HTTP 1.1) is a "draft standard". The real reason you shouldn't use RFC 2817 is that it's not the way HTTPS has been widely implemented (it's RFC 2818). – Bruno Jan 22 '12 at 19:44

2 Answers2

4

As I was saying in this answer, I'm generally against the use of automatic redirections from http:// to https:// for the reasons you're mentioning. I would certainly not recommend resorting only to bulk mod_rewrite-style redirections for securing a site.

However, in your case, by the time the request reaches the server, it's too late. If there is a MITM, he has done his attack (or part of it) before you got the request.

The best you can do by then is to reply without any useful content. In this case, a redirection (using 301 or 302 and the Location header) could be appropriate. However, it may hide problems if the user (or even you as a developer) ignores the warnings (in this case, the browser will follow the redirection and retry the request almost transparently).

Therefore, I would simply suggest returning a 404 status:

  • http://yoursite/ and https://yoursite/ are effectively two distinct sites. There is no reason to expect a 1:1 mapping of all resources from the URI spaces from one to the other (just in the same way as you could have a completely different hierarchy for ftp://yoursite/).
  • More importantly, this is a problem that should be treated upstream: the link that led your user to this resource using http:// should be considered as broken. Don't make it work automatically. Having a 404 status for a resource that shouldn't be there is fine. In addition, returning an error message when there is an error is good: it will force you (or at least remind you) as a developer that you need to fix the page/form/link that led to this problem.

Dropping the connection is just a bonus, if you can do this with this framework: it will only be really useful if it can be sent asynchronously by the server (before the client has finished sending the request), if the browser can read it asynchronously (in which case it should stop sending immediately when there is an error) and if the MITM attacker is passive (an active MITM could stop the response to go back through the client and make sure the client sends all the request by consuming it with its own "proxy", whether or not the server has dropped the connection). These conditions can happen, but fixing the problem at the source is still better anyway.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Thank you for that very thoughtful answer Bruno. :) – Dave Jan 23 '12 at 17:18
  • Re-reading this a couple of years later... I should point out I'm not actually *against* the use of automatic redirections from `http://` to `https://` (they can be useful), I'm just against sites that use them blindly as some sort of magical tool without considering the other problems associated with this topic. – Bruno Jan 17 '14 at 10:58
  • @Bruno This is something I plan to tackle soon with quite a large site, nothing to do with Django, just to do with redirecting `http` to `https`. I take note of your advice about fixing all the links to make sure they aren't pointing to any `http` locations, I am more worried about users ending up on the `http` equivalent from third-party links or manually typing it in / from browser auto-complete history locations; with that in mind, do you foresee any issues with doing the redirection site wide? – Brett May 25 '18 at 17:16
2

If you are using Nginx as your front-end proxy then you can use another non-standard HTTP status code 444 which closes the connection without sending any headers. http://wiki.nginx.org/HttpRewriteModule#return It would require that Nginx know enough about which urls to deny on HTTP.

Mark Lavin
  • 24,664
  • 5
  • 76
  • 70