web-dev-qa-db-ja.com

DjangoベースのサイトにHTTPSのみを使用させようとしていますが、安全かどうかわかりませんか?

EFFは すべての場所でHTTPSを使用 をサイトで推奨しています。 Djangoを使用してログインページにHTTPSを実装することについて質問したとき、それは確かに 私が得た応答 :)でした

だから私はまさにそれをやろうとしている。 HTTPS専用に構成しようとしているDjango/nginxセットアップがあります。これは一種の動作しますが、問題があります。さらに重要なのは、httpsプレフィックスが表示されていても、本当にsecureであるかどうかです。

すべてのhttpページをhttpsにリダイレクトするようにnginxを構成しましたが、その部分は機能します。ただし... https://mysite.com/search/というページに、検索フォーム/ボタンが付いているとします。 Djangoはフォームを処理し、http://mysite.com/search/results?term="foo"であるresultsページにリダイレクトします。

このURLはブラウザーに送信され、ブラウザーはbackをnginxサーバーに送信します。nginxサーバーは、httpsで始まるバージョンのページに永続的にリダイレクトします。 (少なくとも私はそれが起こっていることだと思います-確かにIEは私が安全でないページに行くことを警告し、次に戻って安全なページ:)

しかし、これは本当に安全ですか?または、少なくとも標準のHTTPS専用サイトと同じくらいのセキュリティがありますか? Djangoがhttp-prefix URLを送信し、誰かがセキュリティを危険にさらしているという事実ですか?はい、私が知る限り、https-prefixがあるページのみが返信されますが、それだけです'tfeelright :)このサイトが証明できるように、セキュリティはファンキーで、何か足りないものがあるのではないかと心配しています。

63
John C

Cookieを保護する

settings.py に行を入れます

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

cookieはHTTPS接続経由でのみ送信されます。さらに、おそらくSESSION_EXPIRE_AT_BROWSER_CLOSE=Trueも必要です。古いバージョンのDjango(1.4未満))を使用している場合、セキュリティで保護されたCSRF Coo​​kieの設定はありません。簡単な修正として、CSRF Coo​​kieを安全にするには、セッションCookieはSESSION_COOKIE_SECURE=Trueを編集することで安全です(Django/middleware/csrf.py):

class CsrfViewMiddleware(object):
   ...
   def process_response(self, request, response):
       ...
       response.set_cookie(settings.CSRF_COOKIE_NAME,
            request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
            domain=settings.CSRF_COOKIE_DOMAIN,
            secure=settings.SESSION_COOKIE_SECURE or None)

HTTPリクエストをウェブサーバーのHTTPSに送信する

次に、nginxで、httpリクエストをhttpsにリダイレクトする書き換えルールが必要です。

server {
   listen 80;
   rewrite ^(.*) https://$Host$1 permanent;
}

Djangoのreverse関数とurlテンプレートタグは相対リンクのみを返します。したがって、httpsページを表示している場合、リンクはhttpsサイトにとどまります。

OS環境変数HTTPSをオンに設定します

最後に、(および私の元の応答ではこれを除外しました)、OS環境変数HTTPS'on'に対して有効にする必要があります。Djangoは、完全に生成されたリンクにhttpsを付加します(例:HttpRedirectRequestsなど)mod_wsgiを使用している場合は、次の行を追加できます。

os.environ['HTTPS'] = "on"

wsgiスクリプト に。 uwsgiを使用している場合は、コマンドラインスイッチ--env HTTPS=on、またはuwsgi env = HTTPS=onファイルに行.iniを追加することで、環境変数を追加できます。他に何も機能しない場合の最後の手段として、設定ファイルを編集してimport osos.environ['HTTPS'] = "on"の行を含めることもできますが、これらも機能するはずです。

Wsgiを使用している場合は、環境変数wsgi.url_scheme'https'に追加して、settings.pyに追加することができます。

os.environ['wsgi.url_scheme'] = 'https'

Vijayendra Bapteのコメント によるwsgiのアドバイス。

Django/http/__init__.pyを読むと、この環境変数の必要性を確認できます。

def build_absolute_uri(self, location=None):
    """
    Builds an absolute URI from the location and the variables available in
    this request. If no location is specified, the absolute URI is built on
    ``request.get_full_path()``.
    """
    if not location:
        location = self.get_full_path()
    if not absolute_http_url_re.match(location):
        current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
                                     self.get_Host(), self.path)
        location = urljoin(current_uri, location)
    return iri_to_uri(location)

def is_secure(self):
    return os.environ.get("HTTPS") == "on"

追加のWebサーバーの事柄:

あの男のアドバイス を取り、nginxに行を追加してWebサーバーのHSTSヘッダーをオンにします。

add_header Strict-Transport-Security max-age=31536000;

これは、今後10年間のWebサイトがHTTPSのみを使用することをWebブラウザーに通知します。同じブラウザーからの今後の訪問に対して中間者攻撃がある場合(たとえば、ページのHTTPバージョンにリダイレクトするコーヒーショップの悪意のあるルーターにログオンする場合)、ブラウザーは覚えています。 HTTPSのみであることになっており、誤って情報をあきらめないようにします。ただし、これに注意してください。変更することはできません。後でドメインの一部をHTTPで提供することを決定できます(この行を削除してから10年が経過するまで)。したがって、事前に計画してください。たとえば、アプリケーションの人気がすぐに高まる可能性があり、手頃な価格でHTTPSを適切に処理できない大きなCDNを使用する必要がある場合、問題が発生する可能性があります。

また、弱いプロトコルを無効にしてください。ドメインを SSLテスト に送信して、潜在的な問題(短すぎるキー、TLSv1.2を使用していない、壊れたプロトコルを使用しているなど)を確認します。たとえば、nginxでは私が使用します:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
67
dr jimbob

Http://から対応するhttps://ページにリダイレクトするのは間違ったアプローチです。ポート80を https://yourdomain.ext/ にリダイレクトするようにnginxを設定します

server {
       listen 80;
       rewrite ^/? https://$Host/ permanent;
 }

または同様(近くの次のnginxマニュアルを確認してください)、ポート80(http)でアプリケーションを実行しないでください。したがって、ポート80での他のリクエストは404または類似のものに解決されます(アプリが安全になり、リンクが https://yourdomain.ext/ を指すhttpsでのみ実行されるようにカスタマイズしてください) 。次に、リスンポート443(https)でのみアプリを実行します。コード内で相対パスを使用すると、すべてが完全なhttps://パスに解決され、httpからhttpsへのバウンスを回避できるため、安全です。

3
esskar

さらに、nginxから HSTS-Header を送信して、クライアント(ブラウザ)にHTTPSのみを使用することを示す必要があります。

add_header Strict-Transport-Security max-age=31536000;

一般的な設定では、httpsトラフィックをWebサーバー(つまりNginx)からDjangoアプリを実行しているローカルhttpサーバーに転送します。

この場合、SECURE_PROXY_SSL_HEADER設定を使用する方が簡単です(Django 1.4以降で使用可能)。

https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER

3
Sebastian

私が探しているのはDjango httphttpsに書き換えるミドルウェアです。 SO に関するこの質問では、1つの回答が thisミドルウェア を指しています。おそらく、独自のミドルウェアを作成しますが、それは簡単なはずです(SOについての焦点を絞った質問は、開始に支援が必要な場合、正しい方向に向けられます)。

2
bstpierre

受け入れられた回答で説明されているように、ほとんどの場合、Apacheまたは何かをhttpsにリダイレクトするように設定できます。できれば、パフォーマンスとDjangoの外部で提供されるファイルの方が良いでしょう。

しかし、できない場合、またはデバッグを行いたい場合は、Django最近(1.8)がhttps-redirectsの1つとしてSecurityMiddlewareを導入したことを指摘しておきますいくつかの機能。

詳細は ドキュメント を参照してください。基本的に、Django.middleware.security.SecurityMiddlewareとセットSECURE_SSL_REDIRECT = True

(受け入れられた回答で言及されているヘッダーは、このミドルウェアによっても設定できます。)

2
Mark

Djangoのいずれかを生成するには、

  1. https://domain/pathhttps:スキームとリンクし、
  2. //domain/pathスキームなしのリンク(ブラウザーはこれらを現在開いているページと同じスキームを持つものとして解釈します)、または
  3. /pathリンクはスキームもドメインもありません(ブラウザはこれらが現在指しているページと同じスキームとドメインを持つと解釈します)。
1
yfeldblum