Erreur de connexion CSRF après la mise à niveau vers 2.5.0.beta4

Après la mise à niveau vers 2.5.0.beta4, je vois des erreurs CSRF dans le journal de production :

Traitement par SessionController#csrf en JSON
Terminé 200 OK en 1 ms (Vues : 0,1 ms | ActiveRecord : 0,0 ms | Allocations : 351)
Début de la requête POST "/session" pour 127.0.0.1 le 2020-05-05 09:25:17 +0000
Traitement par SessionController#create en */*
  Paramètres : {"login" => "admin", "password" => "[FILTRÉ]", "second_factor_method" => "1", "timezone" => "Europe/Berlin"}
Impossible de vérifier l'authenticité du jeton CSRF.
  Rendu du modèle texte
  Modèle texte rendu (Durée : 0,0 ms | Allocations : 1)
  La chaîne de filtres s'est arrêtée car :verify_authenticity_token a rendu ou redirigé
Terminé 403 Forbidden en 2 ms (Vues : 0,7 ms | Allocations : 1100)

Et Discourse Doctor affiche :

========================================
Discourse 2.5.0.beta4
Version de Discourse sur forum.netzwissen.de : Discourse 2.5.0.beta4
Version de Discourse sur localhost : NON TROUVÉE
==================== PROBLÈME DNS ====================
Ce serveur signale NON TROUVÉE, mais forum.netzwissen.de signale Discourse 2.5.0.beta4.
Cela suggère que vous avez un problème DNS ou qu'un proxy intermédiaire est en cause.
Si vous utilisez Cloudflare ou un CDN, il est possible qu'il soit mal configuré.

Question : le serveur héberge lui-même plusieurs services avec différents noms DNS. Devant Discourse, nous avons un serveur HAProxy pour gérer la terminaison SSL. Je ne comprends pas le message d’erreur :

“Version de Discourse sur localhost : NON TROUVÉE”

Est-il possible que l’erreur CSRF soit liée à ce message d’erreur ?

Discourse-doctor ne prétend pas pouvoir diagnostiquer une configuration complexe comme la vôtre. Il se contente de comparer si l’hôte local et le DNS renvoient la même valeur. Pour votre configuration, il est normal qu’ils soient différents.

Cependant, je n’ai aucune indication concernant votre problème réel. Désolé.

Bonjour,

Ok, j’ai testé avec un autre compte et j’obtiens le même message d’erreur. Il semble que les connexions soient totalement bloquées maintenant et que l’erreur CSRF puisse en être la cause racine…

Des idées pour un débogage plus approfondi ? Mon app.yml est assez standard, sauf que :

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

Les requêtes entrantes sont acheminées depuis un serveur haproxy vers le conteneur Discourse sur le port 884. Le SSL/HTTPS est géré par haproxy.

Lors de l’enregistrement d’un nouvel utilisateur via oauth2 (Google), je rencontre également une erreur CSRF :

 Rendu de common/_discourse_stylesheet.html.erb (Durée : 0,4 ms | Allocations : 206)
  Rendu de application/_header.html.erb (Durée : 0,3 ms | Allocations : 142)
Terminé 200 OK en 23 ms (Vues : 20,4 ms | ActiveRecord : 0,0 ms | Allocations : 4636)
Démarrage de GET "/latest.json?order=default" pour 127.0.0.1 le 2020-05-05 11:43:08 +0000
Traitement par ListController#latest au format JSON
  Paramètres : {"order"=>"default"}
Terminé 200 OK en 30 ms (Vues : 0,1 ms | ActiveRecord : 0,0 ms | Allocations : 10224)
Démarrage de GET "/u/hp.json" pour 127.0.0.1 le 2020-05-05 11:43:08 +0000
Traitement par UsersController#get_honeypot_value au format JSON
Terminé 200 OK en 3 ms (Vues : 0,1 ms | ActiveRecord : 0,0 ms | Allocations : 1049)
Démarrage de GET "/session/csrf" pour 127.0.0.1 le 2020-05-05 11:43:38 +0000
Traitement par SessionController#csrf au format JSON
Terminé 200 OK en 1 ms (Vues : 0,2 ms | ActiveRecord : 0,0 ms | Allocations : 355)
Démarrage de POST "/auth/google_oauth2" pour 127.0.0.1 le 2020-05-05 11:43:38 +0000
(google_oauth2) Point de terminaison de configuration détecté, exécution en cours.
(google_oauth2) Phase de demande initiée.
Démarrage de GET "/auth/failure?message=csrf_detected" pour 127.0.0.1 le 2020-05-05 11:43:38 +0000
Traitement par Users::OmniauthCallbacksController#failure au format HTML
  Paramètres : {"message"=>"csrf_detected"}
  Rendu de users/omniauth_callbacks/failure.html.erb dans layouts/no_ember
  Rendu de users/omniauth_callbacks/failure.html.erb dans layouts/no_ember (Durée : 0,1 ms | Allocations : 20)
  Rendu de layouts/_head.html.erb (Durée : 11,7 ms | Allocations : 3551)
  Rendu de common/_discourse_stylesheet.html.erb (Durée : 0,5 ms | Allocations : 213)
  Rendu de application/_header.html.erb (Durée : 0,9 ms | Allocations : 555)
Terminé 200 OK en 19 ms (Vues : 16,4 ms | ActiveRecord : 0,0 ms | Allocations : 7652)

J’ai rencontré exactement le même problème après la mise à niveau vers 2.5.0.beta4 (Moved site behind proxy, favicon and header not using https anymore - #7 by rossierd).

Avez-vous réussi à résoudre le problème ? Je peux imaginer que la mise à niveau est accompagnée d’une nouvelle version de nginx (ou de sa configuration) qui entraîne ce problème (mais c’est purement hypothétique ;-)).
J’ai cherché un moyen de désactiver CSRF dans nginx (GitHub - gartnera/nginx_csrf_prevent: Prevent CSRF with nginx · GitHub), mais je pense que nginx doit être recompilé, et je ne sais pas si nous avons besoin de l’environnement de développement complet de Discourse pour le faire.

Malheureusement, le problème n’est toujours pas résolu ici. La connexion échoue avec l’erreur « erreur inconnue » et à chaque tentative, je vois ceci dans le journal :

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)

Le fichier app.yml contient :

## 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"

comme recommandé dans https://meta.discourse.org/t/haproxy-and-discourse-ip-issue/92387

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

J’ai réussi à me connecter avec cela, mais faites attention à l’endroit où vous modifiez la commande proxy_pass. Cela ne fonctionne que dans location @discourse { .. }

Ok, juste pour comprendre : nous parlons bien du nginx dans la « zoo de conteneurs », c’est cela ? Parce qu’avant la mise à jour vers 2.5.0beta4, il n’y avait aucune nécessité de corriger cela, cela fonctionnait simplement sans problème.

Oui, si par zoo vous entendez le conteneur qui exécute Discourse. Vous pouvez accéder au conteneur avec “rails enter app”.

Nous avons effectué d’autres débogages ici : le problème commence au niveau du serveur nginx à l’intérieur du conteneur. Il ne comprend pas la directive proxy_pass et semble donc planter, mais pourquoi :

root@develd:/var/discourse# docker ps -a
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS                     PORTS                   NAMES
f8f6103a036d        local_discourse/app                "/sbin/boot"             35 seconds ago      Up 32 seconds              127.0.0.1:884->80/tcp   app
43406c37f403        discourse/base:2.0.20200512-1735   "ruby -e 'require 'y…"   2 hours ago         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: "proxy_pass" directive is not allowed here in /etc/nginx/conf.d/discourse.conf:10

J’utilise cette configuration nginx dans app.yml :

## 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;
        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; <-- Ce que j'ai modifié
        proxy_pass http://discourse;
        types {
  - exec: echo "End of custom commands"

Je pense que vous n’avez pas besoin de ce proxy_pass directement dans votre app.yml. Ma configuration ressemble à ceci :

  after_bundle_exec:
    # C'est l'astuce pour transmettre les adresses IP à Discourse
    # Voir 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 {

Mais mon code peut provenir d’une période antérieure au passage à Debian dans les conteneurs.

Vous pourriez essayer de modifier directement ce fichier à l’intérieur du conteneur et de redémarrer nginx.

Pour être certain, dans le conteneur lui-même, modifiez le fichier /etc/nginx/conf.d/discourse.conf et appliquez le correctif comme indiqué ci-dessus.
Ensuite, redémarrez nginx comme suit :

$ service nginx stop
$ service nginx start

et voyez ce qui se passe…

L’astuce de Jays était correcte : j’ai simplement supprimé proxy_pass et tout a fonctionné. La configuration finale dans app.yml est :

## Toutes les commandes personnalisées à exécuter après la construction
run:
  - exec: echo "Début des commandes personnalisées"
  ## Si vous souhaitez définir l'adresse e-mail 'From' pour votre première inscription, décommentez et modifiez :
  ## Après avoir reçu le premier e-mail d'inscription, re-commentez la ligne. Elle ne doit être exécutée qu'une seule fois.
  ## - 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; <--- Ce que j'ai modifié
        types {
  - exec: echo "Fin des commandes personnalisées"