para python django thread-local

python - para - include django



¿Por qué es malo usar locales de subprocesos en Django? (3)

A pesar de que puede mezclar datos de diferentes usuarios, se debe evitar el uso de subprocesos locales porque ocultan una dependencia. Si pasa argumentos a un método, verá y sabrá lo que está pasando. Pero un hilo local es algo así como un canal oculto en el fondo y se puede preguntar, que un método no funciona correctamente en algunos casos.

En algunos casos, los locales de hilo son una buena opción, ¡pero deben usarse con poca frecuencia y cuidado!

Estoy usando hilos locales para almacenar el usuario actual y solicitar objetos. De esta forma, puedo acceder fácilmente a la solicitud desde cualquier parte del programa (por ejemplo, formularios dinámicos) sin tener que pasarlos por alto.

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

Este documento ha sido modificado para sugerir evitar 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 usuales de portabilidad y predictibilidad que generalmente implican las variables globales.

Más importante aún, desde el punto de vista de la seguridad, los threadlocals suponen un gran riesgo. Al proporcionar un almacén de datos que expone el estado de otros hilos, proporciona una forma de que un hilo en su servidor web modifique potencialmente el estado de otro hilo en el sistema. Si los datos locales de thread contienen descripciones de usuarios u otros datos relacionados con la autenticación, esos datos podrían usarse como base para un ataque que otorgue acceso a un usuario no autorizado o exponer detalles privados de un usuario. Si bien es posible construir 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 tal vulnerabilidad 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 muchas personas cómo podrían hackear mi aplicación si leen este artículo y saben que estoy usando conversaciones locales, sin embargo, nadie ha podido decirme. Estoy empezando a sospechar que esta es una opinión sostenida por los puristas que dividen el cabello que adoran pasar los objetos explícitamente.


Estoy totalmente en desacuerdo. TLS es extremadamente útil. Se debe usar con cuidado, al igual que los globals se deben usar con cuidado; pero decir que no debería usarse en absoluto es tan ridículo como decir que los globales nunca deben usarse.

Por ejemplo, almaceno la solicitud actualmente activa en TLS. Esto hace que sea accesible desde mi clase de registro, sin tener que pasar la solicitud a través de cada interfaz, incluidos muchos que no se preocupan por Django en absoluto. Me permite hacer entradas de registro desde cualquier parte del código; el registrador da salida a una tabla de base de datos, y si una solicitud pasa a estar activa cuando se realiza un registro, registra cosas como el usuario activo y lo que se solicitó.

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

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


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)