disable csrfmiddlewaretoken csrf_token python ajax django csrf

python - csrfmiddlewaretoken - Comprobación de Django CSRF con una solicitud POST de Ajax



django post csrf token (17)

para alguien que se encuentra con esto y está intentando depurar:

1) el cheque django csrf (suponiendo que estés enviando uno) está here

2) En mi caso, la settings.CSRF_HEADER_NAME . CSRF_HEADER_NAME se estableció en ''HTTP_X_CSRFTOKEN'' y mi llamada AJAX enviaba un encabezado llamado ''HTTP_X_CSRF_TOKEN'' para que las cosas no funcionaran. Podría cambiarlo en la llamada AJAX o en la configuración django.

3) Si optas por cambiarlo del lado del servidor, busca la ubicación de instalación de django y csrf middleware un punto de interrupción en el csrf middleware csrf .f estás usando virtualenv , será algo así como: ~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py

import ipdb; ipdb.set_trace() # breakpoint!! if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX, # and possible for PUT/DELETE. request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '''')

Luego, asegúrese de que el token csrf se csrf correctamente de request.META

4) Si necesita cambiar su encabezado, etc., cambie esa variable en su archivo de configuración

Podría usar algo de ayuda para cumplir con el mecanismo de protección CSRF de Django a través de mi publicación de AJAX. He seguido las instrucciones aquí:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

Copié exactamente el código de muestra de AJAX que tienen en esa página:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

Puse una alerta imprimiendo el contenido de getCookie(''csrftoken'') antes de la llamada xhr.setRequestHeader y de hecho se llena con algunos datos. No estoy seguro de cómo verificar que el token sea correcto, pero me alienta que encuentre y envíe algo.

Pero Django aún rechaza mi publicación de AJAX.

Aquí está mi JavaScript:

$.post("/memorize/", data, function (result) { if (result != "failure") { get_random_card(); } else { alert("Failed to save card data."); } });

Aquí está el error que estoy viendo de Django:

[23 / Feb / 2011 22:08:29] "POST / memorize / HTTP / 1.1" 403 2332

Estoy seguro de que me estoy perdiendo algo, y tal vez es simple, pero no sé qué es. He buscado alrededor de SO y vi información sobre cómo desactivar el chequeo CSRF para mi vista a través del decorador csrf_exempt , pero me parece poco atractivo. Lo intenté y funciona, pero prefiero que mi POST funcione como Django fue diseñado para esperarlo, si es posible.

En caso de que sea útil, esta es la esencia de lo que mi vista está haciendo:

def myview(request): profile = request.user.profile if request.method == ''POST'': """ Process the post... """ return HttpResponseRedirect(''/memorize/'') else: # request.method == ''GET'' ajax = request.GET.has_key(''ajax'') """ Some irrelevent code... """ if ajax: response = HttpResponse() profile.get_stack_json(response) return response else: """ Get data to send along with the content of the page. """ return render_to_response(''memorize/memorize.html'', """ My data """ context_instance=RequestContext(request))

¡Gracias por tus respuestas!


Acabo de encontrar una situación un poco diferente pero similar. No estoy 100% seguro de si sería una resolución para su caso, pero resolví el problema para Django 1.3 estableciendo un parámetro POST ''csrfmiddlewaretoken'' con la cadena de valor de cookie adecuada que generalmente se devuelve en forma de HTML de su hogar por Django''s sistema de plantilla con la etiqueta ''{% csrf_token%}''. No probé con el viejo Django, simplemente sucedió y resolvió con Django1.3. Mi problema fue que la primera solicitud enviada a través de Ajax desde un formulario se realizó con éxito, pero el segundo intento desde el mismo falló, dio como resultado 403 estado aunque el encabezado ''X-CSRFToken'' también se colocó correctamente con el valor de token CSRF como en el caso del primer intento. Espero que esto ayude.

Saludos,

Hiro


Agregue esta línea a su código jQuery:

$.ajaxSetup({ data: {csrfmiddlewaretoken: ''{{ csrf_token }}'' }, });

y hecho.


Aquí hay una solución menos detallada provista por Django:

<script type="text/javascript"> // using jQuery var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } // set csrf header $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); // Ajax call here $.ajax({ url:"{% url ''members:saveAccount'' %}", data: fd, processData: false, contentType: false, type: ''POST'', success: function(data) { alert(data); } }); </script>

Fuente: https://docs.djangoproject.com/en/1.11/ref/csrf/


El problema es porque django espera que el valor de la cookie se transmita como parte de los datos del formulario. El código de la respuesta anterior es obtener javascript para buscar el valor de la cookie y ponerlo en los datos del formulario. Esa es una manera encantadora de hacerlo desde un punto de vista técnico, pero se ve un poco detallado.

En el pasado, lo he hecho más simple al obtener el javascript para poner el valor del token en los datos de la publicación.

Si usa {% csrf_token%} en su plantilla, obtendrá un campo de formulario oculto emitido que conlleva el valor. Pero, si usas {{csrf_token}} obtendrás el valor simple del token, para que puedas usar esto en javascript como este ....

csrf_token = "{{ csrf_token }}";

Luego puede incluir eso, con el nombre de clave requerido en el hash que luego envía como datos a la llamada ajax.


En mi caso, el problema fue con la configuración de nginx que he copiado desde el servidor principal a una temporal con la desactivación de https que no es necesaria en el segundo en el proceso.

Tuve que comentar estas dos líneas en la configuración para que funcione nuevamente:

# uwsgi_param UWSGI_SCHEME https; # uwsgi_pass_header X_FORWARDED_PROTO;


La respuesta aceptada probablemente sea una pista falsa. La diferencia entre Django 1.2.4 y 1.2.5 era el requisito para un token CSRF para las solicitudes AJAX.

Encontré este problema en Django 1.3 y fue causado por la cookie CSRF que no se estableció en primer lugar. Django no configurará la cookie a menos que sea necesario. Por lo tanto, un sitio exclusivamente o altamente ajax que se ejecute en Django 1.2.4 posiblemente nunca haya enviado un token al cliente y entonces la actualización que requiera el token provocará los errores 403.

La solución ideal está aquí: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
pero tendrías que esperar 1.4 a menos que esto sea solo documentación que se ponga al día con el código

Editar

Tenga en cuenta también que los documentos posteriores de Django notan un error en jQuery 1.5, así que asegúrese de estar utilizando 1.5.1 o posterior con el código sugerido por Django: http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax


Parece que nadie ha mencionado cómo hacer esto en JS puro usando el encabezado X-CSRFToken y {{ csrf_token }} , así que aquí hay una solución simple donde no necesitas buscar a través de las cookies o el DOM:

var xhttp = new XMLHttpRequest(); xhttp.open("POST", url, true); xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}"); xhttp.send();


Respuesta no jquery:

var csrfcookie = function() { var cookieValue = null, name = ''csrftoken''; if (document.cookie && document.cookie !== '''') { var cookies = document.cookie.split('';''); for (var i = 0; i < cookies.length; i++) { var cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) == (name + ''='')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; };

uso:

var request = new XMLHttpRequest(); request.open(''POST'', url, true); request.setRequestHeader(''Content-Type'', ''application/x-www-form-urlencoded; charset=UTF-8''); request.setRequestHeader(''X-CSRFToken'', csrfcookie()); request.onload = callback; request.send(data);


Se asigna un token CSRF a cada sesión (es decir, cada vez que inicie sesión). Entonces, antes de desear obtener algunos datos ingresados ​​por el usuario y enviarlos como una llamada ajax a alguna función que esté protegida por el decorador csrf_protect, intente encontrar las funciones que se están llamando antes de obtener estos datos del usuario. Por ejemplo, se debe representar una plantilla en la que el usuario ingresa datos. Esa plantilla está siendo renderizada por alguna función. En esta función, puede obtener el token csrf de la siguiente manera: csrf = request.COOKIES [''csrftoken''] Ahora pase este valor csrf en el diccionario de contexto con el que se está representando la plantilla en cuestión. Ahora en esa plantilla, escriba esta línea: ahora en su función javascript, antes de hacer una solicitud ajax, escriba esto: var csrf = $ (''# csrf''). Val () esto seleccionará el valor del token pasado a la plantilla y lo almacenará en variable csrf. Ahora, al hacer una llamada ajax, en los datos de su publicación, pase este valor también: "csrfmiddlewaretoken": csrf

Esto funcionará incluso si no está implementando formularios django.

De hecho, la lógica aquí es: necesitas un token que puedes obtener de la solicitud. Así que solo necesita averiguar la función a la que se llama inmediatamente después de iniciar sesión. Una vez que tenga este token, realice otra llamada ajax para obtenerla o páselo a alguna plantilla a la que pueda acceder su ajax.



Si tu formulario se publica correctamente en Django sin JS, deberías poder mejorarlo progresivamente con ajax sin ningún tipo de piratería o paso desordenado del token csrf. Simplemente serialice todo el formulario y eso recogerá automáticamente todos los campos de su formulario, incluido el campo csrf oculto:

$(''#myForm'').submit(function(){ var action = $(this).attr(''action''); var that = $(this); $.ajax({ url: action, type: ''POST'', data: that.serialize() ,success: function(data){ console.log(''Success!''); } }); return false; });

He probado esto con Django 1.3+ y jQuery 1.5+. Obviamente, esto funcionará para cualquier formulario HTML, no solo para las aplicaciones de Django.


Si usa la función $.ajax , simplemente puede agregar el token csrf en el cuerpo de datos:

$.ajax({ data: { somedata: ''somedata'', moredata: ''moredata'', csrfmiddlewaretoken: ''{{ csrf_token }}'' },


Usa Firefox con Firebug. Abra la pestaña ''Consola'' mientras dispara la solicitud de Ajax. Con DEBUG=True , obtienes la buena página de error django como respuesta e incluso puedes ver el html renderizado de la respuesta ajax en la pestaña de la consola.

Entonces sabrás cuál es el error.


puedes pegar este js en tu archivo html, recuerda ponerlo antes de la función js

<script> // using jQuery function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '''') { var cookies = document.cookie.split('';''); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + ''='')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $(document).ready(function() { var csrftoken = getCookie(''csrftoken''); $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); }); </script>


{% csrf_token %} puesto en plantillas html dentro de <form></form>

se traduce a algo así como:

<input type=''hidden'' name=''csrfmiddlewaretoken'' value=''Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR'' />

Entonces, ¿por qué no solo grep en su JS de esta manera?

token = $("#change_password-form").find(''input[name=csrfmiddlewaretoken]'').val()

y luego pásalo, por ejemplo, haciendo un POST, como:

$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){ console.log(data); });


Solución real

Ok, logré rastrear el problema. Se encuentra en el código Javascript (como sugerí a continuación).

Lo que necesitas es esto:

$.ajaxSetup({ beforeSend: function(xhr, settings) { function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '''') { var cookies = document.cookie.split('';''); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + ''='')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) { // Only send the token to relative URLs i.e. locally. xhr.setRequestHeader("X-CSRFToken", getCookie(''csrftoken'')); } } });

en lugar del código publicado en los documentos oficiales: http://docs.djangoproject.com/en/1.2/ref/contrib/csrf/#ajax

El código de trabajo proviene de esta entrada de Django: http://www.djangoproject.com/weblog/2011/feb/08/security/

Entonces, la solución general es: "use el controlador ajaxSetup en lugar del manejador ajaxSend". No sé por qué funciona. Pero funciona para mí :)

Publicación anterior (sin respuesta)

Estoy experimentando el mismo problema en realidad.

Ocurre después de actualizar a Django 1.2.5 - no hubo errores con las solicitudes AJAX POST en Django 1.2.4 (AJAX no estaba protegido de ninguna manera, pero funcionó bien).

Al igual que OP, probé el fragmento de JavaScript publicado en la documentación de Django. Estoy usando jQuery 1.5. También estoy usando el middleware "django.middleware.csrf.CsrfViewMiddleware".

Traté de seguir el código del middleware y sé que falla en esto:

request_csrf_token = request.META.get(''HTTP_X_CSRFTOKEN'', '''')

y entonces

if request_csrf_token != csrf_token: return self._reject(request, REASON_BAD_TOKEN)

este "si" es verdadero, porque "request_csrf_token" está vacío.

Básicamente significa que el encabezado NO está establecido. Entonces, ¿hay algo malo con esta línea JS?

xhr.setRequestHeader("X-CSRFToken", getCookie(''csrftoken''));

?

Espero que los detalles proporcionados nos ayuden a resolver el problema :)