web-dev-qa-db-ja.com

Django / nginxでHTTPS専用サイトを展開する方法は?

私の元々の質問は、 Djangoログインページ)のHTTPSを有効にする で、唯一の応答で、私は-サイト全体を作成することをお勧めしましたHTTPSのみとして

Django 1.3とnginxを使用している場合、サイトをHTTPS専用にする正しい方法は何ですか?

1つの応答で ミドルウェアソリューション が言及されましたが、警告がありました。

Djangoは、POSTデータを保持している間、SSLリダイレクトを実行できません。リダイレクトがGET中にのみ発生するようにビューを構成してください。

nginxによるhttpsへの書き換え についてのサーバーフォールトに関する質問、データを失うPOSTの問題についても言及しました。

EFFによるHTTPSのみへの推奨 、次のことに注意してください。

アプリケーションは、設定時にCookieにSecure属性を設定する必要があります。この属性は、安全な(HTTPS)トランスポートを介してのみCookieを送信し、決して安全ではない(HTTP)ようにブラウザに送信するように指示します。

Django-authのようなアプリには、Cookieをセキュアとして設定する機能がありますか?または、さらにミドルウェアを作成する必要がありますか?

したがって、Django/nginxの組み合わせを設定してHTTPSのみを実装する最良の方法は次の点です。

  • 保安
  • POSTデータの保存
  • cookieが適切に処理された
  • 他のDjango=アプリ(Django-authなど)との相互作用、正常に動作
  • 私が知らない他の問題:)

Edit-複数のブラウザのテスト中に発見した別の問題。検索フォーム/ボタンがあるURL https://mysite.com/search/があるとします。ボタンをクリックして、フォームをDjango=通常どおりに処理し、Django HttpResponseRedirect to http://mysite.com/search?results="foo"。]を実行します。 Nginxは、必要に応じてhttps://mysite.com/search?results="foo"にリダイレクトします。

しかし--Operaはリダイレクトが発生したときに可視flashを持ちます。同じ検索語であってもすべての検索が発生します(本当にhttpsキャッシュしない:)さらに悪いことに、IEでテストすると、最初にメッセージが表示されます。

安全でない接続にリダイレクトされようとしています-続行しますか?

[はい]をクリックすると、すぐに次のようになります。

安全な接続でページを表示しようとしています-続行しますか?

2番目のIE警告にはそれをオフにするオプションがあります-first警告にはないため、誰かが検索してリダイレクトされるたびに結果ページには、少なくとも1つの警告メッセージが表示されます。

38
John C

ジョンCの答えの2番目の部分、およびDjango 1.4 + ...

HttpResponseRedirectを拡張する代わりに、_request.scheme_をhttpsに変更できます。 DjangoはNginxのリバースプロキシの背後にあるため、元のリクエストが安全だったことはわかりません。

Django設定で、 SECURE_PROXY_SSL_HEADER 設定を設定します。

_SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
_

次に、Nginxがリバースプロキシでカスタムヘッダーを設定する必要があります。 Nginxサイトの設定:

_location / {
    # ... 
    proxy_set_header X-Forwarded-Proto $scheme;
}
_

このように_request.scheme == 'https'_およびrequest.is_secure()はTrueを返します。 request.build_absolute_uri()は_https://..._などを返します...

52
yprez

ここに私がこれまでに解決した解決策があります。 nginxの構成とDjangoのコードの記述の2つの部分があります。 nginx部分はexternalリクエストを処理し、httpページをhttpsにリダイレクトし、Django=コードハンドルinternalhttpプレフィックスを持つURL生成(少なくとも、HttpResponseRedirect()から生じるもの)。組み合わせて、うまく機能するようです-私が知る限り、クライアントブラウザーはユーザーが自分で入力しなかったhttpページを見ることはありません。

パート1、nginxの構成

_# nginx.conf
# Redirects any requests on port 80 (http) to https:
server {
    listen       80;
    server_name  www.mysite.com mysite.com;
    rewrite ^ https://mysite.com$request_uri? permanent;
#    rewrite ^ https://mysite.com$uri permanent; # also works
}
# Django pass-thru via uWSGI, only from https requests:
server {
    listen       443;
    ssl          on;
    ssl_certificate        /etc/ssl/certs/mysite.com.chain.crt;
    ssl_certificate_key    /etc/ssl/private/mysite.com.key;

    server_name  mysite.com;
    location / {
        uwsgi_pass 127.0.0.1:8088;
        include uwsgi_params;
    }
}
_

パート2 A、settings.pyのさまざまなセキュアCookie設定

SERVER_TYPE = "DEV"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True#現在DjangoのDevブランチのみ。
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

パート2 B、Djangoコード

_# mysite.utilities.decorators.py
import settings

def HTTPS_Response(request, URL):
    if settings.SERVER_TYPE == "DEV":
        new_URL = URL
    else:
        absolute_URL = request.build_absolute_uri(URL)
        new_URL = "https%s" % absolute_URL[4:]
    return HttpResponseRedirect(new_URL)

# views.py

def show_items(request):
    if request.method == 'POST':
        newURL = handle_post(request)
        return HTTPS_Response(request, newURL) # replaces HttpResponseRedirect()
    else: # request.method == 'GET'
        theForm = handle_get(request)
    csrfContext = RequestContext(request, {'theForm': theForm,})
    return render_to_response('item-search.html', csrfContext)

def handle_post(request):
    URL = reverse('item-found') # name of view in urls.py
    item = request.REQUEST.get('item')
    full_URL = '%s?item=%s' % (URL, item)
    return full_URL
_

HTTPS_Response()decoratorとして書き換えることができることに注意してください。利点は、すべてのコードを調べてHttpResponseRedirect()を置き換える必要がないことです。欠点-HttpResponseRedirect()の前にデコレーターを配置する必要があります。これはDjango at _Django.http.__init__.py_。)です。Djangoのコードが、それはあなた次第です-それは確かに1つのオプションです。

20
John C

サイト全体をhttpsの後ろに置いておくと、Djangoの終わりで心配する必要はありません(nginxとDjangoの間でのみデータを保護する必要がないと仮定しますユーザーとサーバー)

5
second