После обновления до версии 2.5.0.beta4 в лог продакшн-окружения я вижу ошибки CSRF:
Processing by SessionController#csrf as JSON
Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.0ms | Allocations: 351)
Started POST "/session" for 127.0.0.1 at 2020-05-05 09:25:17 +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.7ms | Allocations: 1100)
Также утилита Discourse Doctor показывает:
========================================
Discourse 2.5.0.beta4
Discourse version at forum.netzwissen.de: Discourse 2.5.0.beta4
Discourse version at localhost: NOT FOUND
==================== DNS PROBLEM ====================
This server reports NOT FOUND, but forum.netzwissen.de reports Discourse 2.5.0.beta4 .
This suggests that you have a DNS problem or that an intermediate proxy is to blame.
If you are using Cloudflare, or a CDN, it may be improperly configured.
Вопрос: сам сервер хостит несколько сервисов с разными DNS-именами. Перед Discourse стоит сервер HAProxy для завершения SSL. Я не понимаю смысл сообщения об ошибке
“Discourse version at localhost: NOT FOUND”
Возможно ли, что ошибка CSRF связана с этим сообщением?
Discourse-doctor не претендует на то, чтобы диагностировать сложную настройку, как ваша. Он лишь сравнивает, возвращают ли локальный хост и DNS одинаковые значения. Для вашей конфигурации ожидается, что они будут различаться.
К сожалению, у меня нет никаких подсказок относительно вашей реальной проблемы.
Привет!
Хорошо, я протестировал с другой учётной записью и получил то же сообщение об ошибке. Похоже, что входы в систему сейчас полностью заблокированы, и ошибка CSRF может быть первопричиной…
Есть ли какие-либо идеи для дальнейшей отладки? Мой файл app.yml довольно стандартный, за исключением того, что:
expose:
- "127.0.0.1:884:80" # http
Входящие запросы перенаправляются с сервера haproxy в контейнер Discourse на порт 884. SSL/HTTPS обрабатывается через haproxy.
При регистрации нового пользователя через oauth2 (Google) также возникает ошибка CSRF:
Rendered common/_discourse_stylesheet.html.erb (Duration: 0.4ms | Allocations: 206)
Rendered application/_header.html.erb (Duration: 0.3ms | Allocations: 142)
Completed 200 OK in 23ms (Views: 20.4ms | ActiveRecord: 0.0ms | Allocations: 4636)
Started GET "/latest.json?order=default" for 127.0.0.1 at 2020-05-05 11:43:08 +0000
Processing by ListController#latest as JSON
Parameters: {"order"=>"default"}
Completed 200 OK in 30ms (Views: 0.1ms | ActiveRecord: 0.0ms | Allocations: 10224)
Started GET "/u/hp.json" for 127.0.0.1 at 2020-05-05 11:43:08 +0000
Processing by UsersController#get_honeypot_value as JSON
Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.0ms | Allocations: 1049)
Started GET "/session/csrf" for 127.0.0.1 at 2020-05-05 11:43:38 +0000
Processing by SessionController#csrf as JSON
Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 355)
Started POST "/auth/google_oauth2" for 127.0.0.1 at 2020-05-05 11:43:38 +0000
(google_oauth2) Setup endpoint detected, running now.
(google_oauth2) Request phase initiated.
Started GET "/auth/failure?message=csrf_detected" for 127.0.0.1 at 2020-05-05 11:43:38 +0000
Processing by Users::OmniauthCallbacksController#failure as HTML
Parameters: {"message"=>"csrf_detected"}
Rendering users/omniauth_callbacks/failure.html.erb within layouts/no_ember
Rendered users/omniauth_callbacks/failure.html.erb within layouts/no_ember (Duration: 0.1ms | Allocations: 20)
Rendered layouts/_head.html.erb (Duration: 11.7ms | Allocations: 3551)
Rendered common/_discourse_stylesheet.html.erb (Duration: 0.5ms | Allocations: 213)
Rendered application/_header.html.erb (Duration: 0.9ms | Allocations: 555)
Completed 200 OK in 19ms (Views: 16.4ms | ActiveRecord: 0.0ms | Allocations: 7652)
Вам удалось решить проблему? Я могу предположить, что обновление принесло новую версию nginx (или его конфигурацию), что и привело к этой проблеме (но это лишь гипотеза ;-)).
Я попытался найти способ отключить CSRF в nginx (GitHub - gartnera/nginx_csrf_prevent: Prevent CSRF with nginx · GitHub), но, кажется, nginx нужно перекомпилировать, и я не знаю, требуется ли для этого полная среда разработки Discourse.
К сожалению, проблема здесь всё ещё не решена. Вход завершается ошибкой «неизвестная ошибка», и при каждой попытке я вижу в логе следующее:
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)
В файле 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;
types {
- exec: echo "End of custom commands"
У меня получилось успешно войти, но будьте внимательны, где вы вносите исправления в команду proxy_pass. Она работает только внутри блока location @discourse { .. }
Ок, просто для уточнения: мы говорим о nginx внутри «зоопарка контейнеров», верно? Потому что до обновления до версии 2.5.0beta4 необходимости в применении патчей к нему не было, всё работало гладко.
Мы провели дополнительную отладку: проблема начинается на сервере nginx внутри контейнера. Он не понимает директиву proxy_pass и, похоже, падает, но почему:
root@develd:/var/discourse# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8f6103a036d local_discourse/app "/sbin/boot" 35 секунд назад Up 32 секунд 127.0.0.1:884->80/tcp app
43406c37f403 discourse/base:2.0.20200512-1735 "ruby -e 'require 'y…" 2 часа назад 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
В app.yml я использую следующую конфигурацию nginx:
## Любые пользовательские команды для запуска после сборки
run:
- exec: echo "Начало пользовательских команд"
## Если вы хотите установить адрес электронной почты в поле 'From' для вашей первой регистрации, раскомментируйте и измените:
## После получения первого письма о регистрации закомментируйте строку снова. Она должна выполниться только один раз.
## - 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; <-- Что я изменил
proxy_pass http://discourse;
types {
- exec: echo "Конец пользовательских команд"
Чтобы убедиться в этом, внутри контейнера отредактируйте файл /etc/nginx/conf.d/discourse.conf и внесите в него изменения, как указано выше.
Затем перезапустите nginx следующим образом:
Совет Джейса оказался верным: я просто удалил proxy_pass, и всё заработало. Итоговая конфигурация в app.yml:
## Любые пользовательские команды для запуска после сборки
run:
- exec: echo "Начало пользовательских команд"
## Если вы хотите установить адрес электронной почты 'From' для вашей первой регистрации, раскомментируйте и измените:
## После получения первого письма о регистрации закомментируйте строку обратно. Она должна выполниться только один раз.
## - 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; <-- То, что я изменил
types {
- exec: echo "Конец пользовательских команд"