Error de inicio de sesión CSRF después de actualizar a 2.5.0.beta4

Después de actualizar a 2.5.0.beta4, veo errores CSRF en el registro de producción:

Procesando por SessionController#csrf como JSON
Completado 200 OK en 1ms (Vistas: 0.1ms | ActiveRecord: 0.0ms | Asignaciones: 351)
Iniciado POST "/session" para 127.0.0.1 el 2020-05-05 09:25:17 +0000
Procesando por SessionController#create como */*
  Parámetros: {"login"=>"admin", "password"=>"[FILTRADO]", "second_factor_method"=>"1", "timezone"=>"Europe/Berlin"}
No se puede verificar la autenticidad del token CSRF.
  Renderizando plantilla de texto
  Renderizada plantilla de texto (Duración: 0.0ms | Asignaciones: 1)
La cadena de filtros se detuvo porque :verify_authenticity_token renderizó o redirigió
Completado 403 Forbidden en 2ms (Vistas: 0.7ms | Asignaciones: 1100)

Además, discourse doctor muestra:

========================================
Discourse 2.5.0.beta4
Versión de Discourse en forum.netzwissen.de: Discourse 2.5.0.beta4
Versión de Discourse en localhost: NO ENCONTRADO
==================== PROBLEMA DE DNS ====================
Este servidor reporta NO ENCONTRADO, pero forum.netzwissen.de reporta Discourse 2.5.0.beta4.
Esto sugiere que tienes un problema de DNS o que un proxy intermedio es el culpable.
Si estás usando Cloudflare o una CDN, es posible que esté configurada incorrectamente.

Pregunta: el servidor en sí aloja múltiples servicios con diferentes nombres DNS. Delante de Discourse tenemos un servidor haproxy para manejar la terminación SSL. No entiendo el mensaje de error:

“Versión de Discourse en localhost: NO ENCONTRADO”

¿Es posible que el error CSRF esté relacionado con este mensaje de error?

Discourse-doctor no pretende ser capaz de diagnosticar una configuración compleja como la tuya. Solo compara si el host local y el DNS devuelven el mismo valor. Para tu configuración, se espera que sean diferentes.

Sin embargo, no tengo ninguna pista sobre tu problema real. Lo siento.

Hola,
vale, he probado con otra cuenta y obtengo el mismo mensaje de error. Parece que los inicios de sesión están totalmente bloqueados ahora y el error CSRF podría ser la causa raíz…

¿Alguna idea para más depuración? Mi app.yml es bastante estándar, excepto que:

expose:
  - "127.0.0.1:884:80"   # http

Las solicitudes entrantes se reenvían desde un servidor haproxy al contenedor de Discourse en el puerto 884. SSL/HTTPS lo gestiona haproxy.

Al registrar un nuevo usuario mediante OAuth2 (Google), también obtengo un error de CSRF:

 Renderizado common/_discourse_stylesheet.html.erb (Duración: 0.4ms | Asignaciones: 206)
  Renderizado application/_header.html.erb (Duración: 0.3ms | Asignaciones: 142)
Completado 200 OK en 23ms (Vistas: 20.4ms | ActiveRecord: 0.0ms | Asignaciones: 4636)
Iniciado GET "/latest.json?order=default" para 127.0.0.1 el 2020-05-05 11:43:08 +0000
Procesado por ListController#latest como JSON
  Parámetros: {"order"=>"default"}
Completado 200 OK en 30ms (Vistas: 0.1ms | ActiveRecord: 0.0ms | Asignaciones: 10224)
Iniciado GET "/u/hp.json" para 127.0.0.1 el 2020-05-05 11:43:08 +0000
Procesado por UsersController#get_honeypot_value como JSON
Completado 200 OK en 3ms (Vistas: 0.1ms | ActiveRecord: 0.0ms | Asignaciones: 1049)
Iniciado GET "/session/csrf" para 127.0.0.1 el 2020-05-05 11:43:38 +0000
Procesado por SessionController#csrf como JSON
Completado 200 OK en 1ms (Vistas: 0.2ms | ActiveRecord: 0.0ms | Asignaciones: 355)
Iniciado POST "/auth/google_oauth2" para 127.0.0.1 el 2020-05-05 11:43:38 +0000
(google_oauth2) Punto de configuración detectado, ejecutándose ahora.
(google_oauth2) Fase de solicitud iniciada.
Iniciado GET "/auth/failure?message=csrf_detected" para 127.0.0.1 el 2020-05-05 11:43:38 +0000
Procesado por Users::OmniauthCallbacksController#failure como HTML
  Parámetros: {"message"=>"csrf_detected"}
  Renderizando users/omniauth_callbacks/failure.html.erb dentro de layouts/no_ember
  Renderizado users/omniauth_callbacks/failure.html.erb dentro de layouts/no_ember (Duración: 0.1ms | Asignaciones: 20)
  Renderizado layouts/_head.html.erb (Duración: 11.7ms | Asignaciones: 3551)
  Renderizado common/_discourse_stylesheet.html.erb (Duración: 0.5ms | Asignaciones: 213)
  Renderizado application/_header.html.erb (Duración: 0.9ms | Asignaciones: 555)
Completado 200 OK en 19ms (Vistas: 16.4ms | ActiveRecord: 0.0ms | Asignaciones: 7652)

He tenido exactamente el mismo problema después de la actualización a 2.5.0.beta4 (Moved site behind proxy, favicon and header not using https anymore - #7 by rossierd).

¿Lograste solucionar el problema? Me imagino que la actualización vino con una nueva versión de nginx (o su configuración) que provocó este problema (pero es pura hipótesis ;-)).
Intenté buscar una forma de desactivar CSRF en nginx (GitHub - gartnera/nginx_csrf_prevent: Prevent CSRF with nginx · GitHub), pero creo que nginx debe recompilarse, y no sé si necesitamos el entorno de desarrollo completo de Discourse para hacerlo.

Desafortunadamente, el problema aún no está resuelto aquí. El inicio de sesión falla con “error desconocido” y, en cada intento, veo esto en el registro:

root@develd:/var/discourse# tail -f /var/log/discourse-rails/production.log
Processing by SessionController#csrf as JSON
Completed 200 OK in 1ms (Views: 0.1ms | Allocations: 351)
Started POST "/session" for 127.0.0.1 at 2020-06-07 06:58:19 +0000
Processing by SessionController#create as */*
  Parameters: {"login"=>"admin", "password"=>"[FILTERED]", "second_factor_method"=>"1", "timezone"=>"Europe/Berlin"}
Can't verify CSRF token authenticity.
  Rendering text template
  Rendered text template (Duration: 0.0ms | Allocations: 1)
Filter chain halted as :verify_authenticity_token rendered or redirected
Completed 403 Forbidden in 2ms (Views: 0.8ms | ActiveRecord: 0.0ms | Allocations: 1100)
Started GET "/session/csrf" for 127.0.0.1 at 2020-06-07 07:00:45 +0000
Processing by SessionController#csrf as JSON
Completed 200 OK in 1ms (Views: 0.2ms | Allocations: 351)
Started POST "/session" for 127.0.0.1 at 2020-06-07 07:00:45 +0000
Processing by SessionController#create as */*
  Parameters: {"login"=>"admin", "password"=>"[FILTERED]", "second_factor_method"=>"1", "timezone"=>"Europe/Berlin"}
Can't verify CSRF token authenticity.
  Rendering text template
  Rendered text template (Duration: 0.0ms | Allocations: 1)
Filter chain halted as :verify_authenticity_token rendered or redirected
Completed 403 Forbidden in 2ms (Views: 0.9ms | Allocations: 1100)

El archivo app.yml tiene:

## Any custom commands to run after building
run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  ## - exec: rails r "SiteSetting.notification_email='noreply-discourse@netzwissen.de'"
  - replace:
      filename: /etc/nginx/conf.d/discourse.conf
      from: "types {"
      to: |
        set_real_ip_from 127.0.0.0/24;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        types {
  - exec: echo "End of custom commands"

como se recomendó en https://meta.discourse.org/t/haproxy-and-discourse-ip-issue/92387

Prueba esto: Moved site behind proxy, favicon and header not using https anymore - #12 by rossierd

Con eso pude iniciar sesión correctamente, pero ten cuidado dónde aplicas la corrección al comando proxy_pass. Solo funciona en location @discourse { .. }

ok, solo para entender: estamos hablando del nginx dentro del “zoológico de contenedores”, ¿correcto? Porque, antes de la actualización a 2.5.0beta4, no había ningún requisito para parchear esto, simplemente funcionaba sin problemas.

Sí, si por zoológico te refieres al contenedor que está ejecutando Discourse. Puedes entrar al contenedor con “rails enter app”.

Hemos realizado más depuración aquí: el problema comienza en el servidor nginx dentro del contenedor. No entiende la directiva proxy_pass y, por lo tanto, parece fallar, pero ¿por qué:

root@develd:/var/discourse# docker ps -a
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS                     PORTS                   NAMES
f8f6103a036d        local_discourse/app                "/sbin/boot"             35 segundos atrás     Up 32 segundos             127.0.0.1:884->80/tcp   app
43406c37f403        discourse/base:2.0.20200512-1735   "ruby -e 'require 'y…"   hace 2 horas         Created


docker exec -it f8f6103a036d /bin/bash

root@forum:/# tail -f /var/log/nginx/error.log
2020/06/08 19:05:03 [emerg] 288#288: la directiva "proxy_pass" no está permitida aquí en /etc/nginx/conf.d/discourse.conf:10

Estoy usando esta configuración de nginx en app.yml:

## Cualquier comando personalizado para ejecutar después de la compilación
run:
  - exec: echo "Inicio de comandos personalizados"
  ## Si deseas establecer la dirección de correo electrónico 'From' para tu primer registro, descomenta y cambia:
  ## Después de recibir el primer correo de registro, vuelve a comentar la línea. Solo necesita ejecutarse una vez.
  ## - exec: rails r "SiteSetting.notification_email='noreply-discourse@netzwissen.de'"
  - replace:
      filename: /etc/nginx/conf.d/discourse.conf
      from: "types {"
      to: |
        set_real_ip_from 127.0.0.0/24;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        proxy_set_header Host $http_host;
        proxy_set_header X-Request-Start "t=${msec}";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https; # $thescheme; <-- Lo que modifiqué
        proxy_pass http://discourse;
        types {
  - exec: echo "Fin de comandos personalizados"

Creo que no necesitas ese proxy_pass justo ahí en tu app.yml. Mi configuración se ve así:

  after_bundle_exec:
    # Esto es lo mágico para transmitir las direcciones IP a Discourse
    # Ver https://meta.discourse.org/t/last-ip-address-and-action-dispatch-trusted-proxies/50098/3?u=pfaffman
    - replace:
        filename: /etc/nginx/conf.d/discourse.conf
        from: "types {"
        to: |
          set_real_ip_from 192.168.1.0/24;
          set_real_ip_from 172.18.0.0/24;
          set_real_ip_from 172.17.0.0/24;
          real_ip_recursive on;
          real_ip_header X-Forwarded-For;
          types {

Pero es posible que mi código sea anterior al cambio a Debian en los contenedores.

Podrías intentar editar directamente ese archivo dentro del contenedor y reiniciar nginx.

Solo para asegurarnos, dentro del propio contenedor, edite /etc/nginx/conf.d/discourse.conf y aplique el parche al archivo como se indicó anteriormente. Luego, reinicie nginx de la siguiente manera:

$ service nginx stop
$ service nginx start

y observe qué sucede…

El consejo de Jays fue correcto: simplemente eliminé proxy_pass y luego funcionó. La configuración final en app.yml es:

## Cualquier comando personalizado para ejecutar después de la compilación
run:
  - exec: echo "Inicio de comandos personalizados"
  ## Si deseas establecer la dirección de correo electrónico 'De' para tu primer registro, descomenta y modifica:
  ## Después de recibir el primer correo de registro, vuelve a comentar la línea. Solo necesita ejecutarse una vez.
  ## - exec: rails r "SiteSetting.notification_email='noreply-discourse@netzwissen.de'"
  - replace:
      filename: /etc/nginx/conf.d/discourse.conf
      from: "types {"
      to: |
        set_real_ip_from 127.0.0.1/24;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        proxy_set_header Host $http_host;
        proxy_set_header X-Request-Start "t=${msec}";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https; # $thescheme; <-- Lo que modifiqué
        types {
  - exec: echo "Fin de los comandos personalizados"