Após a atualização para a versão 2.5.0.beta4, vejo erros de CSRF no log de produção:
Processando por SessionController#csrf como JSON
Concluído 200 OK em 1ms (Views: 0.1ms | ActiveRecord: 0.0ms | Alocações: 351)
Iniciado POST "/session" para 127.0.0.1 em 2020-05-05 09:25:17 +0000
Processando por SessionController#create como */*
Parâmetros: {"login"=>"admin", "password"=>"[FILTRADO]", "second_factor_method"=>"1", "timezone"=>"Europe/Berlin"}
Não foi possível verificar a autenticidade do token CSRF.
Renderizando template de texto
Template de texto renderizado (Duração: 0.0ms | Alocações: 1)
A cadeia de filtros foi interrompida pois :verify_authenticity_token renderizou ou redirecionou
Concluído 403 Forbidden em 2ms (Views: 0.7ms | Alocações: 1100)
E o Discourse Doctor mostra:
========================================
Discourse 2.5.0.beta4
Versão do Discourse em forum.netzwissen.de: Discourse 2.5.0.beta4
Versão do Discourse em localhost: NÃO ENCONTRADA
==================== PROBLEMA DE DNS ====================
Este servidor relata NÃO ENCONTRADA, mas forum.netzwissen.de relata Discourse 2.5.0.beta4.
Isso sugere que você tem um problema de DNS ou que um proxy intermediário é o culpado.
Se você estiver usando Cloudflare ou uma CDN, ela pode estar configurada incorretamente.
Pergunta: o próprio servidor hospeda vários serviços com nomes DNS diferentes. Na frente do Discourse, temos um servidor HAProxy para lidar com o término SSL. Não entendo a mensagem de erro:
“Versão do Discourse em localhost: NÃO ENCONTRADA”
É possível que o erro de CSRF tenha relação com essa mensagem de erro?
O Discourse-doctor não se propõe a diagnosticar uma configuração complexa como a sua. Ele apenas compara se o host local e o DNS retornam o mesmo valor. Para a sua configuração, é esperado que eles sejam diferentes.
No entanto, não tenho nenhuma dica sobre o seu problema real. Desculpe.
Ok, testei com outra conta e recebi a mesma mensagem de erro. Parece que os logins estão totalmente bloqueados agora e o erro de CSRF pode ser a causa raiz…
Alguma ideia para mais depuração? Meu app.yml é bastante padrão, exceto por:
expose:
- "127.0.0.1:884:80" # http
As solicitações de entrada são encaminhadas de um servidor haproxy para o contêiner discourse na porta 884. O SSL/HTTPS é feito pelo haproxy.
Ao registrar um novo usuário via OAuth2 (Google), também recebo um erro de CSRF:
Renderizado common/_discourse_stylesheet.html.erb (Duração: 0,4ms | Alocações: 206)
Renderizado application/_header.html.erb (Duração: 0,3ms | Alocações: 142)
Concluído 200 OK em 23ms (Views: 20,4ms | ActiveRecord: 0,0ms | Alocações: 4636)
Iniciado GET "/latest.json?order=default" para 127.0.0.1 em 2020-05-05 11:43:08 +0000
Processando por ListController#latest como JSON
Parâmetros: {"order"=>"default"}
Concluído 200 OK em 30ms (Views: 0,1ms | ActiveRecord: 0,0ms | Alocações: 10224)
Iniciado GET "/u/hp.json" para 127.0.0.1 em 2020-05-05 11:43:08 +0000
Processando por UsersController#get_honeypot_value como JSON
Concluído 200 OK em 3ms (Views: 0,1ms | ActiveRecord: 0,0ms | Alocações: 1049)
Iniciado GET "/session/csrf" para 127.0.0.1 em 2020-05-05 11:43:38 +0000
Processando por SessionController#csrf como JSON
Concluído 200 OK em 1ms (Views: 0,2ms | ActiveRecord: 0,0ms | Alocações: 355)
Iniciado POST "/auth/google_oauth2" para 127.0.0.1 em 2020-05-05 11:43:38 +0000
(google_oauth2) Endpoint de configuração detectado, executando agora.
(google_oauth2) Fase de solicitação iniciada.
Iniciado GET "/auth/failure?message=csrf_detected" para 127.0.0.1 em 2020-05-05 11:43:38 +0000
Processando 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 (Duração: 0,1ms | Alocações: 20)
Renderizado layouts/_head.html.erb (Duração: 11,7ms | Alocações: 3551)
Renderizado common/_discourse_stylesheet.html.erb (Duração: 0,5ms | Alocações: 213)
Renderizado application/_header.html.erb (Duração: 0,9ms | Alocações: 555)
Concluído 200 OK em 19ms (Views: 16,4ms | ActiveRecord: 0,0ms | Alocações: 7652)
Conseguiu resolver o problema? Imagino que a atualização tenha trazido uma nova versão do nginx (ou de sua configuração), o que levou a esse problema (mas é apenas uma hipótese ;-)).
Tentei encontrar uma maneira de desativar o CSRF no nginx (GitHub - gartnera/nginx_csrf_prevent: Prevent CSRF with nginx · GitHub), mas acho que o nginx precisa ser recompilado, e não sei se precisamos do ambiente de desenvolvimento completo do Discourse para fazer isso.
Infelizmente, o problema ainda não foi resolvido aqui. O login falha com “erro desconhecido” e, a cada tentativa, vejo o seguinte no log:
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)
O app.yml contém:
## 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"
Consegui fazer login com sucesso usando isso, mas tome cuidado onde você aplica o comando proxy_pass. Ele apenas funciona em location @discourse { .. }
ok, só para confirmar: estamos falando do nginx dentro do “zoológico de containers”, certo? Porque, antes da atualização para a 2.5.0beta4, não havia necessidade de aplicar patches nisso, tudo funcionava sem problemas.
Fizemos mais alguns depurações aqui: o problema começa no servidor nginx dentro do container. Ele não entende a diretiva proxy_pass e, portanto, parece travar, mas 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…" 2 horas atrás 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: a diretiva "proxy_pass" não é permitida aqui em /etc/nginx/conf.d/discourse.conf:10
Estou usando esta configuração do nginx no app.yml:
## Quaisquer comandos personalizados para executar após a construção
run:
- exec: echo "Início dos comandos personalizados"
## Se você quiser definir o endereço de e-mail 'De' para o seu primeiro registro, descomente e altere:
## Após receber o primeiro e-mail de cadastro, comente novamente a linha. Ela só precisa ser executada uma 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; <-- O que eu modifiquei
proxy_pass http://discourse;
types {
- exec: echo "Fim dos comandos personalizados"
Acho que você não precisa desse proxy_pass ali no seu app.yml. Minha configuração fica assim:
after_bundle_exec:
# Este é o truque para transmitir os números de IP para o Discourse
# Veja 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 {
Mas meu código pode ser de antes da mudança para o Debian nos containers.
Você pode tentar apenas editar esse arquivo dentro do container e reiniciar o nginx.
Só para confirmar, dentro do próprio container, edite /etc/nginx/conf.d/discourse.conf e aplique o patch no arquivo conforme mostrado acima.
Em seguida, reinicie o nginx da seguinte forma:
A dica do Jays estava correta: eu apenas removi proxy_pass e então funcionou. A configuração final em app.yml é:
## Qualquer comando personalizado para executar após a construção
run:
- exec: echo "Início dos comandos personalizados"
## Se você quiser definir o endereço de e-mail 'De' para seu primeiro registro, descomente e altere:
## Após receber o primeiro e-mail de cadastro, comente novamente a linha. Ela só precisa ser executada uma 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; <-- O que eu modifiquei
types {
- exec: echo "Fim dos comandos personalizados"