56

スレッドローカルを使用して、現在のユーザーとリクエストオブジェクトを保存しています。このようにして、プログラムのどこからでも(動的フォームなど)リクエストに簡単にアクセスできます。リクエストを渡す必要はありません。

ミドルウェアにスレッドローカルストレージを実装するために、Djangoサイトのチュートリアルに従いました: https ://web.archive.org/web/20091128195932/http://code.djangoproject.com:80 / wiki / CookBookThreadlocalsAndUser

その後、このドキュメントは、この手法を回避することを提案するように変更されました: https ://web.archive.org/web/20110504132459/http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser

記事から:

設計の観点から、スレッドローカルは本質的にグローバル変数であり、グローバル変数が通常伴う移植性と予測可能性のすべての通常の問題の影響を受けます。

さらに重要なことに、セキュリティの観点から、スレッドローカルは大きなリスクをもたらします。他のスレッドの状態を公開するデータストアを提供することにより、Webサーバー内の1つのスレッドが、システム内の別のスレッドの状態を変更する可能性がある方法を提供します。スレッドローカルデータにユーザーの説明やその他の認証関連データが含まれている場合、そのデータは、許可されていないユーザーへのアクセスを許可したり、ユーザーの個人情報を公開したりする攻撃の基礎として使用される可能性があります。この種の攻撃から安全なスレッドローカルシステムを構築することは可能ですが、防御的であり、そもそもそのような脆弱性の影響を受けないシステムを構築する方がはるかに簡単です。

グローバル変数が悪い理由は理解できますが、この場合、自分のサーバーで自分のコードを実行しているため、2つのグローバル変数がどのような危険をもたらすのかわかりません。

誰かが関連するセキュリティの問題を説明できますか?この記事を読んで、私がスレッドローカルを使用していることを知っている場合、多くの人に私のアプリケーションをハッキングする方法を尋ねましたが、誰も私に言うことができませんでした。私は、これがオブジェクトを明示的に渡すことを愛する髪を分割する純粋主義者によって保持された意見であると疑うようになり始めています。

4

4 に答える 4

54

私は完全に同意しません。TLSは非常に便利です。グローバルを注意して使用するのと同じように、注意して使用する必要があります。しかし、それをまったく使用すべきではないと言うことは、グローバルを決して使用すべきではないと言うのと同じくらいばかげています。

たとえば、現在アクティブなリクエストをTLSに保存します。これにより、Djangoをまったく気にしない多くのインターフェースを含め、すべてのインターフェースを介してリクエストを渡すことなく、ロギングクラスからアクセスできるようになります。コード内のどこからでもログエントリを作成できます。ロガーはデータベーステーブルに出力し、ログが作成されたときに要求がアクティブである場合、アクティブなユーザーや要求されていたものなどをログに記録します。

あるスレッドに別のスレッドのTLSデータを変更する機能を持たせたくない場合は、これを禁止するようにTLSを設定します。これには、おそらくネイティブTLSクラスを使用する必要があります。しかし、その議論には説得力がありません。攻撃者がバックエンドとして任意のPythonコードを実行できる場合、システムはすでに致命的な危険にさらされています。たとえば、攻撃者は、後で別のユーザーとして実行するために、モンキーパッチを適用する可能性があります。

明らかに、リクエストの最後にTLSをクリアする必要があります。Djangoでは、ミドルウェアクラスのprocess_responseとprocess_exceptionでクリアすることを意味します。

于 2010-07-12T10:06:27.397 に答える
14

異なるユーザーからのデータを混同する可能性があるという事実にもかかわらず、スレッドローカルは依存関係を隠すため、避ける必要があります。メソッドに引数を渡すと、何を渡しているかがわかります。しかし、ローカルスレッドはバックグラウンドの隠しチャネルのようなものであり、メソッドが正しく機能しない場合があるのではないかと思うかもしれません。

スレッドローカルが良い選択である場合もありますが、それらはめったに注意深く使用されるべきではありません!

于 2010-07-12T09:36:09.347 に答える
13

最新のDjango1.10と互換性のあるTLSミドルウェアを作成する方法の簡単な例:

# coding: utf-8
# Copyright (c) Alexandre Syenchuk (alexpirine), 2016

try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()

def get_current_request():
    return getattr(_thread_locals, 'request', None)

def get_current_user():
    request = get_current_request()
    if request:
        return getattr(request, 'user', None)

class ThreadLocalMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        _thread_locals.request = request
        return self.get_response(request)
于 2016-09-04T05:22:57.057 に答える
3

この質問は本当に古いですが、誰かがそれを参照しているのを見たので、この質問で引用されたwikiページは2010年にスレッドローカルストレージの推奨を停止し、2012年までに完全に削除されたことに注意してください。

于 2019-10-06T20:01:57.413 に答える