¿Por qué es malo el uso de subprocesos locales en Django?

Estoy utilizando los locales de subprocesos para almacenar el usuario actual y solicitar objetos. De esta manera, puedo acceder fácilmente a la solicitud desde cualquier parte del progtwig (por ejemplo, formularios dynamics) sin tener que pasarlos.

Para implementar el almacenamiento de subprocesos locales en un middleware, seguí un tutorial en el sitio de Django: http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser?version=18

Este documento se ha modificado desde entonces para sugerir que se evite esta técnica: http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser?version=20

Del artículo:

Desde el punto de vista del diseño, los threadlocals son esencialmente variables globales, y están sujetos a todos los problemas habituales de portabilidad y previsibilidad que las variables globales generalmente conllevan.

    Más importante aún, desde un punto de vista de seguridad, los threadlocals representan un gran riesgo. Al proporcionar un almacén de datos que expone el estado de otros subprocesos, proporciona una manera para que un subproceso en su servidor web modifique potencialmente el estado de otro subproceso en el sistema. Si los datos de subprocesos contienen descripciones de usuarios u otros datos relacionados con la autenticación, esos datos podrían utilizarse como base para un ataque que otorga acceso a un usuario no autorizado o expone los detalles privados de un usuario. Si bien es posible crear un sistema threadlocal que esté a salvo de este tipo de ataque, es mucho más fácil estar a la defensiva y construir un sistema que no esté sujeto a ninguna vulnerabilidad de este tipo en primer lugar.

    Entiendo por qué las variables globales pueden ser malas, pero en este caso estoy ejecutando mi propio código en mi propio servidor, por lo que no puedo ver qué peligro representan dos variables globales.

    ¿Alguien puede explicar el problema de seguridad involucrado? Le he preguntado a mucha gente cómo piratearían mi aplicación si leyeran este artículo y supieran que estoy usando hilos locales, pero nadie ha podido decirme. Estoy empezando a sospechar que esta es una opinión sostenida por los puristas escandalosos que aman pasar objetos explícitamente.

    No estoy de acuerdo por completo. TLS es extremadamente útil. Se debe usar con cuidado, al igual que los globales se deben usar con cuidado; pero decir que no debe usarse en absoluto es tan ridículo como decir que los globales no deberían usarse nunca.

    Por ejemplo, almaceno la solicitud actualmente activa en TLS. Esto lo hace accesible desde mi clase de registro, sin tener que pasar la solicitud a través de todas las interfaces, incluidas muchas que no se preocupan por Django en absoluto. Me permite hacer entradas de registro desde cualquier parte del código; el registrador se envía a una tabla de base de datos, y si una solicitud está activa cuando se realiza un registro, registra cosas como el usuario activo y lo que se estaba solicitando.

    Si no desea que un subproceso tenga la capacidad de modificar los datos TLS de otro subproceso, configure su TLS para prohibir esto, lo que probablemente requiera el uso de una clase TLS nativa. Sin embargo, no encuentro convincente ese argumento; Si un atacante puede ejecutar un código Python arbitrario como su backend, su sistema ya está comprometido fatalmente, por ejemplo, podría ejecutar un parche para cualquier cosa que se ejecute más tarde como un usuario diferente.

    Obviamente, querrá borrar cualquier TLS al final de una solicitud; en Django, eso significa borrarlo en process_response y process_exception en una clase de middleware.

    A pesar del hecho de que podría mezclar datos de diferentes usuarios, se deben evitar los locales de subprocesos porque ocultan una dependencia. Si pasa argumentos a un método que ve y sabe lo que está pasando. Pero un hilo local es algo así como un canal oculto en el fondo y puede que se pregunte si un método no funciona correctamente en algunos casos.

    Hay algunos casos en los que los locales de hilos son una buena opción, ¡pero deben usarse con poca frecuencia y con cuidado!

    Un ejemplo rápido sobre cómo crear un middleware TLS compatible con el último Django 1.10:

     # 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)