Djangoの非アクティブのためにセッションを期限切れにする方法は?


93

Djangoアプリケーションには、次のセッション管理要件があります。

  1. ユーザーがブラウザを閉じると、セッションは期限切れになります。
  2. 非アクティブな期間が経過すると、セッションは期限切れになります。
  3. 非アクティブが原因でセッションが期限切れになるタイミングを検出し、適切なメッセージをユーザーに表示します。
  4. 非アクティブ期間が終了する数分前にセッションの期限が切れることをユーザーに警告します。警告とともに、セッションを延長するオプションをユーザーに提供します。
  5. ユーザーがアプリ内でサーバーに送信されるリクエストを含まない長いビジネスアクティビティで作業している場合、セッションがタイムアウトしてはなりません。

ドキュメント、Djangoコード、およびこれに関連するいくつかのブログ投稿を読んだ後、次の実装アプローチを思いつきました。

要件1
この要件は、SESSION_EXPIRE_AT_BROWSER_CLOSEをTrueに設定することで簡単に実装できます。

要件2
セッションの有効期限を設定するためにSESSION_COOKIE_AGEを使用するいくつかの推奨事項を見ました。しかし、この方法には次のような問題があります。

  • ユーザーがアプリケーションをアクティブに使用している場合でも、セッションは常にSESSION_COOKIE_AGEの終了時に期限切れになります。(これは、カスタムミドルウェアを使用してすべてのリクエストでセッションの有効期限をSESSION_COOKIE_AGEに設定するか、SESSION_SAVE_EVERY_REQUESTをtrueに設定してすべてのリクエストでセッションを保存することで防ぐことができます。ただし、SESSION_COOKIE_AGEを使用するため、次の問題は避けられません。)

  • Cookieの動作方法により、SESSION_EXPIRE_AT_BROWSER_CLOSEとSESSION_COOKIE_AGEは相互に排他的です。つまり、Cookieはブラウザを閉じるか、指定された有効期限で期限切れになります。SESSION_COOKIE_AGEが使用され、Cookieの有効期限が切れる前にユーザーがブラウザーを閉じた場合、Cookieは保持され、ブラウザーを再度開くと、ユーザー(または他のユーザー)は再認証されずにシステムにアクセスできます。

  • Djangoは、存在するCookieのみに依存して、セッションがアクティブかどうかを判断します。セッションに保存されているセッションの有効期限はチェックしません。

この要件を実装し、上記の問題を回避するには、次の方法を使用できます。

  • SESSION_COOKIE_AGEは設定しないでください。
  • セッションの有効期限を、すべてのリクエストで「現在時刻+非アクティブ期間」に設定します。
  • SessionMiddlewareでprocess_requestをオーバーライドし、セッションの有効期限を確認します。有効期限が切れている場合は、セッションを破棄してください。

要件3
(上記のカスタムSessionMiddlewareで)セッションの有効期限が切れたことを検出したら、リクエストに属性を設定してセッションの有効期限を示します。この属性は、ユーザーに適切なメッセージを表示するために使用できます。

要件4
JavaScriptを使用してユーザーの非アクティブを検出し、警告を提供し、セッションを延長するオプションも提供します。ユーザーが延長したい場合は、キープアライブパルスをサーバーに送信してセッションを延長します。

要件5
JavaScriptを使用して(長時間のビジネスオペレーション中の)ユーザーアクティビティを検出し、キープアライブパルスをサーバーに送信して、セッションが期限切れにならないようにします。


上記の実装アプローチは非常に手の込んだように見え、より簡単な方法(特に要件2の場合)があるのではないかと思っていました。

どんな洞察も高く評価されます。


3
詳細なソリューションを提供するための+1
Don

あなたが必要とすることをするかもしれないミドルウェアがあります。githubおよびpypi
gbutler

1
「Cookieの動作方法により、SESSION_EXPIRE_AT_BROWSER_CLOSEとSESSION_COOKIE_AGEは相互に排他的です。つまり、Cookieはブラウザーの終了時または指定された有効期限で期限切れになります。SESSION_COOKIE_AGEが使用され、Cookieの期限が切れる前にユーザーがブラウザーを閉じた場合、Cookieは保持され、再び開きますブラウザは、ユーザー(または他の誰でも)が再認証されることなくシステムにアクセスできるようにします。」私が間違っている場合は修正してください。しかし、これは新しいDjangoバージョンではもう当てはまらないようです。(少なくとも
1.5

1
「Djangoは、存在するCookieのみに依存して、セッションがアクティブかどうかを判断します。セッションで保存されたセッションの有効期限はチェックしません。」これはもう本当ではありません。
knaperek 2017

回答:


44

ここにアイデアがあります... SESSION_EXPIRE_AT_BROWSER_CLOSE設定でブラウザのセッションを終了してください。次に、リクエストごとにセッションにタイムスタンプを設定します。

request.session['last_activity'] = datetime.now()

そして、セッションが期限切れになったかどうかを検出するミドルウェアを追加します。このようなものはプロセス全体を処理するはずです...

from datetime import datetime
from django.http import HttpResponseRedirect

class SessionExpiredMiddleware:
    def process_request(request):
        last_activity = request.session['last_activity']
        now = datetime.now()

        if (now - last_activity).minutes > 10:
            # Do logout / expire session
            # and then...
            return HttpResponseRedirect("LOGIN_PAGE_URL")

        if not request.is_ajax():
            # don't set this for ajax requests or else your
            # expired session checks will keep the session from
            # expiring :)
            request.session['last_activity'] = now

次に、いくつかのURLとビューを作成して、セッションの有効期限に関する関連データをajax呼び出しに返す必要があります。

ユーザーがセッションを「更新」することを選択した場合、いわば、しなければならないことはrequeset.session['last_activity']、現在の時刻に再度設定されることです。

明らかに、このコードはほんの始まりに過ぎません...しかし、それはあなたを正しい道に連れて行くはずです


私はここでは懐疑的ですが、if not request.is_ajax()完全に安全だとは思いません。セッションの有効期限が切れる前になりすましを取得したり、ajax呼び出しを送信してセッションを続行したりすることはできませんか?
notbad.jpeg

2
@ notbad.jpeg:一般に、「アクティビティ」は簡単に偽装できます。セッションを保持してリクエストを送信し続ける人は、ただアクティブです。
RemcoGerlich 2014

これは素晴らしい答えです。ミドルウェアは、Django開発において非常に活用されていないツールです。
Jamie Counsell

30

私はDjangoを使うのがかなり新しいです。

ログに記録されたユーザーがブラウザーを閉じるか、一定時間アイドル(非アクティブタイムアウト)になると、セッションを期限切れにしたかったのです。私がそれを理解するためにググったとき、このSOF質問が最初に思い付きました。すばらしい回答のおかげで、Djangoのリクエスト/レスポンスサイクルでミドルウェアがどのように機能するかを理解するためのリソースを調べました。とても役に立ちました。

ここのトップアンサーに続いて、コードにカスタムミドルウェアを適用しようとしていました。しかし、ここでのベストアンサーは2011年に編集されたので、私はまだ少し不審でした。最近の検索結果から少しだけ検索に時間をかけ、簡単な方法を考え出しました。

SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True

私は他のブラウザをチェックしませんでしたが、クロムをチェックしました。1. SESSION_COOKIE_AGEが設定されていても、ブラウザを閉じるとセッションが終了しました。2. 10秒以上アイドルだった場合のみ、セッションの有効期限が切れました。SESSION_SAVE_EVERY_REQUESTのおかげで、新しいリクエストが発生するたびに、セッションが保存され、タイムアウトが更新されて期限切れになります

このデフォルトの動作を変更するには、SESSION_SAVE_EVERY_REQUEST設定をTrueに設定します。Trueに設定すると、Djangoはリクエストごとにセッションをデータベースに保存します。

セッションCookieは、セッションが作成または変更された場合にのみ送信されることに注意してください。SESSION_SAVE_EVERY_REQUESTがTrueの場合、セッションCookieはリクエストごとに送信されます。

同様に、セッションCookieが送信されるたびに、セッションCookieの期限切れ部分が更新されます。

ジャンゴマニュアル1.10

私のようにDjangoを初めて使う人もいるので、私が行った方法のように解決策を見つけるのに多くの時間を費やさないように、私は答えを残します。


26

django-session-securityはまさにそれを行います...

...追加要件があります。サーバーが応答しない場合、または攻撃者がインターネット接続を切断した場合:とにかく有効期限が切れます。

Disclamer:私はこのアプリをメンテナンスしています。しかし、私はこのスレッドを非常に長い間見てきました:)


1
クールなアプリ-うまく設計され、よく構築されています。素敵できれいなコード...ありがとう。
nicorellius 14

ユーザーが離れるときにユーザーがブラウザーまたはタブを(ログアウトせずに)閉じた場合でも、ユーザーはログアウトする必要がありますか?この状態を処理しますか?
Mehmet Kagan Kayaalp 2016

それは、pure-httpセッションのcookieの有効期限によって処理されませんか?
jpic

10

2番目の要件を満たす簡単な方法の1つは、settings.pyのSESSION_COOKIE_AGE値を適切な秒数に設定することです。例えば:

SESSION_COOKIE_AGE = 600      #10 minutes.

ただし、これを行うだけで、ユーザーが何らかの活動を行っているかどうかに関係なく、セッションは10分後に期限切れになります。この問題に対処するために、ユーザーが次の文を含むあらゆる種類のリクエストを実行するたびに、有効期限を自動的に更新できます(さらに10分延長)。

request.session.set_expiry(request.session.get_expiry_age())

2
SESSION_COOKIE_AGE = 600これにより、新しいページリクエストまたはページの更新があるたびにセッションの経過時間が延長されます
Aseem

1
設定だけSESSION_COOKIE_AGEで十分で、リクエスト(セッションCookieの送信)によってセッションCookieの有効期限が自動的に更新されることを確認しました。
ブルーノdesthuilliers


3

最初のリクエストでは、セッションの有効期限を次のように設定できます

self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds 

そして、access_keyとトークンを使用すると、

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.