[pyar] [Django] Como cachear cuando hay CSRF tokens?

Andres Riancho andres.riancho en gmail.com
Jue Jul 17 16:14:58 ART 2014


No lo probe, pero mientras buscaba soluciones lo encontré y leí el
codigo. Basicamente trae aparejado el mismo problema (con caching) que
la implementacion por defecto de CSRF en django; ya que en este caso
en vez de usar una cookie csrf* usa la sessionid* de Django, la cual
también invalidaría el cache (si no haces nada especial).

2014-07-17 16:02 GMT-03:00 Esteban Castro <ecastroborsani en gmail.com>:
> Hola!, probaste https://github.com/mozilla/django-session-csrf ??
>
>
> El 17 de julio de 2014, 9:25, Andres Riancho <andres.riancho en gmail.com>
> escribió:
>
>> Gracias a todos por responder! Les cuento lo que hice al final, para
>> que algun otro que este perdido con esto pueda usar mi experiencia de
>> estos dias.
>>
>>     Lo que proponen en la lista es agregar este codigo JS:
>>
>> // JS code
>> $.ajax({
>>     url: // your csrf url,
>>     type: 'GET',
>>     data: {type: 'login'},  // only if you need a session id for cookie
>> login
>>     dataType: 'json',
>>     success: function(data) {
>>         $('form').each(function() {
>>             $(this).append(
>>                 '<input type=hidden name=csrfmiddlewaretoken ' +
>>                     ' value="' + data.token + '">');
>>         });
>>     }
>> });
>>
>>     No renderear el {{ csrftoken }} en en template, y tomarlo de una
>> view que se ve similar a:
>>
>> // Django code
>> # views.py, don't forget to add to urls.py
>> def get_csrf(request):
>>     if request.GET.get('type') == 'login':
>>         request.session.set_test_cookie()
>>     return JSONResponse({
>>         'status': 1,
>>         'token': getattr(request, 'csrf_token', 'NOTPROVIDED')
>>     })
>>
>>     De esta manera, cualquier usuario que accede al site ve el mismo
>> HTML (que en el mejor de los casos sale del cache) y el CSRF token se
>> agrega una vez que el HTML se cargó. Se puede mejorar ese JS haciendo
>> que se cargue el token solo cuando el form esté visible/activo/siendo
>> completado por el usuario para no tener +1 request HTTP que luego no
>> se use.
>>
>>     El problema que puede traer esto es la manera en la cual se
>> verifica el token CSRF. La verificacion de CSRF en Django, por
>> default, envia un input hidden con un valor random y envia el mismo
>> valor en una session cookie. Esta cookie es definitivamente mala para
>> los caches:
>>
>> "Varnish will, in the default configuration, not cache a object coming
>> from the backend with a Set-Cookie header present. Also, if the client
>> sends a Cookie header, Varnish will bypass the cache and go directly
>> to the backend." [0]
>>
>>     Veamos que pasaría con la solucion propuesta de CSRF token por JS:
>>
>> 1- HTTP GET /
>> 2- Respuesta 200 OK sin cookies con el HTML del cache
>>
>> 3- HTTP GET /csrf-token
>> 4- Respuesta 200 OK con Set-Cookie para verificar luego CSRF
>>         Set-Cookie: csrftoken=3hUXXXR9niBQVBwQsCqtsbzNZugFx1pH;
>> expires=Thu, 16-Jul-2015 12:12:01 GMT; Max-Age=31449600; Path=/;
>> secure
>>
>> 5- HTTP POST /form (usa cookie csrf)
>> 6- Respuesta 200 OK del backend (no cache). Esto esta perfecto, nunca
>> vamos a esperar que Varnish (u otro cache) responda a un POST. En este
>> caso que tenga la cookie de csrf no cambia nada.
>>
>> # El usuario sigue navegando por el site despues de haber completado el
>> form
>>
>> 7- HTTP GET /about-us (usa cookie csrf)
>>     * La cookie se envia porque como vemos arriba:
>>         - El path es / (todo el domain)
>>         - La expiración es larga (horas)
>> 8- Respuesta 200 OK proveniente del backend! <------ MALO
>>     * Notar que cualquier otro usuario que hubiese navegado
>> directamente a /about-us, sin previamente haber obtenido el token CSRF
>> de la pagina principal donde esta el form, hubiese realizado el
>> request SIN cookies, y entonces obtenido la respuesta del cache.
>>
>> Uf! Que problema... entonces? Entonces hay que configurar el cache de
>> alguna manera especial o tomar la (potencialmente) arriesgada decision
>> de deshabilitar CSRF para los forms.
>>
>> Luego de analizar mi situacion especifica, no siendo esto lo mejor
>> para todos los casos! Deshabilite CSRF tokens para los formularios que
>> estan pre-login. De esta manera el problema inicial: "Como cacheo HTML
>> que tiene tokens csrf?" y tambien el caso que enumeraba antes
>> desaparecen.
>>
>> Otro detalle que me encontré es que el tracker de Google Analytics
>> setea una cookie, la cual es enviada tambien al site. Si no se sacan
>> estas cookies [1], el cache va a ir hasta el backend para obtener la
>> respuesta cada vez, haciendo que el cache sea simplemente un
>> pasa-manos.
>>
>> Espero les sirva!
>>
>> [0] https://www.varnish-cache.org/docs/3.0/tutorial/cookies.html
>> [1] https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
>>
>> 2014-07-16 21:24 GMT-03:00 Pedro Jose Pezzarini <jose2190 en gmail.com>:
>> > Crea un service que solo retorne un csrftoken, y antes de enviar el
>> > formulario, anexá el token como un input en hidden.
>> >
>> > El html te va a quedar cacheado y solo vas a enviar el token anexado.
>> >
>> > Espero te sirva mis 2 centavos.
>> >
>> > Saludos!
>> >
>> >
>> > El 16 de julio de 2014, 21:10, ken248000 en gmail.com <ken248000 en gmail.com>
>> > escribió:
>> >
>> >> Django carga el token en una cookie llamada "csrftoken",
>> >> Deberias poder obtenerla con javascript y setear el input csrf de tu
>> >> form.
>> >>
>> >>
>> >> 2014-07-14 16:19 GMT-03:00 Andres Riancho <andres.riancho en gmail.com>:
>> >>
>> >>> Ezequiel,
>> >>>
>> >>>     Gracias por la pronta respuesta, tu propuesta de usar AJAX es algo
>> >>> que querría evitar si es posible, principalmente porque agrega un HTTP
>> >>> request para la carga del form (o al menos para la carga del token).
>> >>> Con las opciones que estaba viendo, y referencie en el email original,
>> >>> todo se cargaría en un solo request HTTP y sin  cambiar nada del
>> >>> codigo front-end.
>> >>>
>> >>>     Entiendo que no existe una solución perfecta y que posiblemente
>> >>> tenga que ir por este workaround pero... no hay nada mejor?
>> >>>
>> >>> Saludos,
>> >>>
>> >>> 2014-07-14 16:11 GMT-03:00 Ezequiel Gonzalez Rial <gonrial en gmail.com>:
>> >>> > Hola Andrés,
>> >>> >
>> >>> > Si vas a cachear olvidate del CSRF. La idea de cachear es que no
>> >>> > tengas
>> >>> > carga dinámica. Si tal como estás diciendo lo que necesitas es que
>> >>> > todas las
>> >>> > vistas tengan un formulario, entonces lo que te recomiendo es que
>> >>> > uses
>> >>> > AJAX
>> >>> > para hacer esa parte de la carga. De esa forma, lo estático se carga
>> >>> > rápido
>> >>> > y cacheado y después podes aplicar toda la lógica necesaria para que
>> >>> > ese
>> >>> > formulario aparezca como tiene que procesarse.
>> >>> >
>> >>> > Saludos,
>> >>> >
>> >>> > Ezequiel
>> >>> >
>> >>> >
>> >>> > El 14 de julio de 2014, 15:50, Andres Riancho
>> >>> > <andres.riancho en gmail.com>
>> >>> > escribió:
>> >>> >>
>> >>> >> Lista,
>> >>> >>
>> >>> >>     Estuve leyendo bastante sobre como hacer caching del HTML
>> >>> >> generado
>> >>> >> por views en Django y los problemas que existen (un gran resumen
>> >>> >> aqui
>> >>> >> [0]); llegando a la conclusión principal de que hacer caching bien
>> >>> >> es
>> >>> >> dificil ;) y como secundaria que existen distintas maneras de
>> >>> >> hacerlo:
>> >>> >>
>> >>> >>  * Varnish + ESI: No me gusto mucho ya que en las workstations de
>> >>> >> los
>> >>> >> devs habría que instalar Varnish, configurarlo, etc.
>> >>> >>
>> >>> >>  * Two phase template rendering con cosas como django-phased [1],
>> >>> >> django-twophase [2] o el partial caching de django-adv-cache-tag
>> >>> >> [3].
>> >>> >> Ninguno de estos proyectos, salvo quizás django-adv-cache-tag
>> >>> >> tienen
>> >>> >> muchos releases/contribuciones/actividad; por lo que me da la
>> >>> >> impresión de que no estoy yendo por el camino correcto.
>> >>> >>
>> >>> >>     Entonces, que me recomiendan para hacer caching de views en
>> >>> >> sites
>> >>> >> con Django? Cual es el mejor approach para los tokens CSRF si por
>> >>> >> ejemplo tengo un contact form en el footer de todas mis views?
>> >>> >>
>> >>> >> [0]
>> >>> >>
>> >>> >> https://groups.google.com/forum/#!topic/django-developers/EojHkVKxVWc
>> >>> >> [1] http://django-phased.readthedocs.org/en/latest/
>> >>> >> [2] https://launchpad.net/django-twophase
>> >>> >> [3] http://documentup.com/twidi/django-adv-cache-tag
>> >>> >>
>> >>> >> Saludos,
>> >>> >> --
>> >>> >> Andrés Riancho
>> >>> >> Project Leader at w3af - http://w3af.org/
>> >>> >> Web Application Attack and Audit Framework
>> >>> >> Twitter: @w3af
>> >>> >> GPG: 0x93C344F3
>> >>> >> _______________________________________________
>> >>> >> pyar mailing list pyar en python.org.ar
>> >>> >> http://listas.python.org.ar/listinfo/pyar
>> >>> >>
>> >>> >> PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>> >>> >>
>> >>> >> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre
>> >>> >> de
>> >>> >> Argentina - http://www.usla.org.ar
>> >>> >
>> >>> >
>> >>> >
>> >>> > _______________________________________________
>> >>> > pyar mailing list pyar en python.org.ar
>> >>> > http://listas.python.org.ar/listinfo/pyar
>> >>> >
>> >>> > PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>> >>> >
>> >>> > La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre
>> >>> > de
>> >>> > Argentina - http://www.usla.org.ar
>> >>>
>> >>>
>> >>>
>> >>> --
>> >>> Andrés Riancho
>> >>> Project Leader at w3af - http://w3af.org/
>> >>> Web Application Attack and Audit Framework
>> >>> Twitter: @w3af
>> >>> GPG: 0x93C344F3
>> >>> _______________________________________________
>> >>> pyar mailing list pyar en python.org.ar
>> >>> http://listas.python.org.ar/listinfo/pyar
>> >>>
>> >>> PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>> >>>
>> >>> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>> >>> Argentina - http://www.usla.org.ar
>> >>
>> >>
>> >>
>> >> _______________________________________________
>> >> pyar mailing list pyar en python.org.ar
>> >> http://listas.python.org.ar/listinfo/pyar
>> >>
>> >> PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>> >>
>> >> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>> >> Argentina - http://www.usla.org.ar
>> >
>> >
>> >
>> > _______________________________________________
>> > pyar mailing list pyar en python.org.ar
>> > http://listas.python.org.ar/listinfo/pyar
>> >
>> > PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>> >
>> > La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>> > Argentina - http://www.usla.org.ar
>>
>>
>>
>> --
>> Andrés Riancho
>> Project Leader at w3af - http://w3af.org/
>> Web Application Attack and Audit Framework
>> Twitter: @w3af
>> GPG: 0x93C344F3
>> _______________________________________________
>> pyar mailing list pyar en python.org.ar
>> http://listas.python.org.ar/listinfo/pyar
>>
>> PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>>
>> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>> Argentina - http://www.usla.org.ar
>
>
>
> _______________________________________________
> pyar mailing list pyar en python.org.ar
> http://listas.python.org.ar/listinfo/pyar
>
> PyAr - Python Argentina - Sitio web: http://www.python.org.ar/
>
> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
> Argentina - http://www.usla.org.ar



-- 
Andrés Riancho
Project Leader at w3af - http://w3af.org/
Web Application Attack and Audit Framework
Twitter: @w3af
GPG: 0x93C344F3


More information about the pyar mailing list