es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Django devuelve “Error de verificación de CSRF. Solicitud cancelada.” detrás de un proxy local de Nginx.

Estoy ejecutando una aplicación Django simple sin ninguna configuración complicada (la mayoría de los valores predeterminados, Django allauth y Django Rest Framework).

La infraestructura para ejecutar tanto localmente como de forma remota se encuentra en un archivo docker-compose:

version: "3"

services:
  web:
    image: web_app
    build:
      context: .
      dockerfile: Dockerfile
    command: gunicorn my_service.wsgi --reload --bind 0.0.0.0:80 --workers 3
    env_file: .env
    volumes:
      - ./my_repo/:/app:z
    depends_on:
      - db
    environment:
      - DOCKER=1

  nginx:
    image: nginx_build
    build:
      context: nginx
      dockerfile: Dockerfile
    volumes:
      - ./my_repo/:/app:z
    ports:
      - "7000:80"

... # db y demás

Como puedes ver, estoy utilizando Gunicorn para servir la aplicación y Nginx como proxy (para archivos estáticos y configuración de Let’s Encrypt). El contenedor de Nginx tiene algunas personalizaciones:

FROM nginx:1.21-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d

Y el archivo nginx.conf es un proxy inverso con una asignación estática:

server {

    listen 80;

    location / {
        proxy_pass http://web;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
    location /static/ {
        alias /app/my_repo/static/;
    }

}

Ejecutar esto en el servidor después de configurar Let’s Encrypt en el contenedor de Nginx funciona sin problemas, pero en la versión local obtengo el error “La verificación CSRF falló. Solicitud abortada” cada vez que envío un formulario (por ejemplo, crear un usuario ficticio en Django Admin). Expongo el puerto web y lo utilizo para enviar los formularios y funciona.

Debido a eso, deduzco que falta algo en la configuración de Nginx o algo que Django necesita saber cómo manejar. Entonces, ¿qué me falta y cómo debería investigar esto?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Parece que el problema está relacionado con la protección CSRF en Django. El middleware CSRF está habilitado de forma predeterminada en Django y requiere que las envíos de formularios incluyan un token CSRF para verificar que la solicitud proviene de una fuente confiable.

    Al utilizar Nginx como proxy inverso, la configuración predeterminada puede interferir con la protección CSRF, ya que puede cambiar las cabeceras de host y puerto en la solicitud, lo que podría invalidar el token CSRF.

    Para solucionar este problema, debes asegurarte de que las cabeceras X-Forwarded-Proto, X-Forwarded-Host y X-Forwarded-Port estén correctamente configuradas en la configuración de Nginx.

    Puedes agregar las siguientes líneas a la configuración de Nginx:

    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    

    Esto asegurará que las cabeceras se configuren correctamente cuando la solicitud se envíe a la aplicación Django.

    Además, es posible que debas agregar la siguiente línea al archivo settings.py de Django:

    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    

    Esto indicará a Django que la aplicación está detrás de un proxy seguro y que debe utilizar la cabecera X-Forwarded-Proto para determinar si se deben servir solicitudes a través de HTTPS.

    Para investigar el problema más a fondo, puedes verificar los registros de Django en busca de mensajes de error relacionados con la validación del token CSRF. También puedes inspeccionar el tráfico de red utilizando una herramienta como Wireshark para ver si las cabeceras se están configurando correctamente en la solicitud.

Comments are closed.