Сохранение сессий пользователей при миграции между хостами

Привет!

Я готовлюсь к миграции нескольких экземпляров Discourse на новый хостинг. План заключается в том, чтобы перевести старый сайт в режим только для чтения, создать резервную копию, перенести её на новый хостинг и восстановить, одновременно обновив настройки DNS (с коротким TTL). Этот процесс полностью основан на руководствах, доступных здесь и в других местах.

Я проводил несколько пробных запусков, используя обходной путь с файлом /etc/hosts для имитации обновления DNS (а также отключив DNS over HTTPS в браузере). Пока всё идёт хорошо.

Однако, несмотря на то, что я тщательно закрываю браузер на «источнике» и открываю его только после завершения миграции на «цели», он забывает, что я был авторизован.

Очевидно, я не хочу, чтобы все участники сайта потеряли авторизацию во время миграции. Куда мне стоит посмотреть или что я упускаю?

Пользователь, с которым я сейчас тестирую, имеет права администратора и использует двухфакторную аутентификацию (2FA). Контейнеры Discourse находятся за Nginx, который завершает SSL-соединение. Это может влиять на проблему.

Заранее спасибо за любые подсказки!

У меня тоже была эта проблема, и я очень хочу её решить.

Буду благодарен за любые подсказки.

Думаю, я попробую создать несколько тестовых аккаунтов без 2FA — вдруг это имеет к чему-то отношение. Очень мало участников сайта используют 2FA, так что, возможно, это приемлемо, если проблема только в потере этих сессий.

Также я проверю, синхронизированы ли исходный и целевой серверы с NTP, хотя, по-моему, сейчас разница между ними не может превышать нескольких секунд.

В остальном, думаю, всегда можно обратиться к исходному коду, чтобы попытаться разобраться, что входит в токен аутентификации и что может вызывать проблему… :grimacing:

Лучше всего уведомить пользователей об изменении: они будут разлогинены и им потребуется войти в систему заново.

У каждого сервера есть уникальная подпись благодаря SSL.

Пользователям будет проще просто войти в систему снова, чем пытаться изменять настройки сервера.

Просто извинитесь за причинённые неудобства, но подчеркните, что это делается ради их же блага.

Но так ли это на самом деле?

Как на session cookies влияют «подписи» SSL (особенно в моём случае, когда новый и старый хосты используют одни и те же файлы SSL-сертификатов на том же доменном имени)?

Хотя я не против извиниться перед участниками (:slightly_smiling_face:), я действительно хочу избежать такого сценария, так как вижу несколько негативных побочных эффектов:

  1. Участники больше не заходят на сайт и с меньшей вероятностью будут участвовать в обсуждении форума в будущем.
  2. Участники забывают свои пароли и нуждаются в помощи для их восстановления.
  3. Участники забывают свои пароли и создают новые учётные записи, оставляя множество «зомби-аккаунтов» на форуме, а также теряя или создавая путаницу с дублирующимися идентичностями без заметок о пользователе или истории сообщений и т. д.

Проблема с SSL работает безупречно перед Discourse (даже с взломом файла hosts), что, если подумать, должно быть так, иначе у балансировщиков нагрузки возникли бы проблемы. Насколько мне известно, Discourse даже не знает о SSL, так как в этой настройке он завершается на Nginx.

Думаю, другой вопрос: «Возможно ли мигрировать сервер Discourse на новый IP без разлогинивания всех пользователей?» Я предполагал, что это возможно, но, возможно, это предположение было ошибочным… :frowning:

Я точно знаю, что мои сессии на форуме переживали резервное копирование и восстановление. Честно говоря, не понимаю, что здесь происходит :frowning:

Сессионные куки шифруются с помощью случайно сгенерированного секретного ключа, который по умолчанию хранится в Redis. Данные Redis не включаются в резервную копию, поэтому при восстановлении сайта на новом сервере генерируется новый секретный ключ.

Вы можете вручную задать секретный ключ, используя переменную окружения DISCOURSE_SECRET_KEY_BASE в файле app.yml. Таким образом, чтобы сохранить сессии, можно попробовать следующее:

  1. На вашем текущем сервере войдите в консоль и найдите секретный ключ в Redis:

    pry(main)> GlobalSetting.safe_secret_key_base
    => "5fb9dc98be368599e0a..."
    
  2. Добавьте DISCOURSE_SECRET_KEY_BASE в секцию env: файла app.yml на старом сервере, используя значение, найденное в шаге (1), и пересоберите приложение. В теории, если всё прошло успешно, Discourse теперь будет использовать значение из app.yml, и пользовательские сессии сохранятся. Вы можете проверить, что переменная окружения используется, выполнив:

    GlobalSetting.secret_key_base
    
  3. Убедитесь, что файл app.yml на новом сервере содержит тот же SECRET_KEY_BASE. При восстановлении резервной копии пользовательские сессии должны сохраниться.

Я не тестировал этот сценарий, поэтому, если вы планируете использовать его для продакшн-форума, обязательно протестируйте его заранее!

Примечание: вы категорически не должны использовать один и тот же секретный ключ для нескольких экземпляров Discourse. Обладание секретным ключом позволит кому-либо расшифровать и изменить свою сессионную куку на сайте, что может иметь очень серьёзные последствия для безопасности.

Отлично — я попробую это на тестовом экземпляре. Посмотрю, смогу ли сообщить, сработает ли это :slight_smile:

Понял. Сейчас думаю, стоит ли создать запрос на добавление функции экспорта этого ключа в резервные копии? Для меня потеря всех сессий на сайте казалась бы «очень плохой ситуацией», учитывая, что на сайте зарегистрированы тысячи аккаунтов. Практическая миграция выявила эту проблему, но, полагаю, если по какой-то причине будет утерян сервер или экземпляр Docker, ключ тоже пропадёт, и мы столкнёмся с той же потерей сессий.

Хорошо бы также упомянуть об этой «функции» в теме о миграции: Move your Discourse Instance to a Different Server

Это тонкое равновесие между безопасностью и удобством.

На данный момент, если кто-то похитит резервную копию Discourse, у него будет доступ ко всем данным форума. Однако он не сможет войти в работающий форум. Пароли хешируются, ключи API хешируются, а куки сессий зашифрованы.

Если бы мы включили секретный ключ в резервную копию, то любой, кто обладает такой копией, мог бы получить доступ к работающему форуму и проводить фишинг, мошенничество и т. д.

Звучит отлично! Мы полностью открыты к созданию темы здесь, на Meta, с объяснением, как мигрировать с секретного ключа Redis на секретный ключ app.yml. Эту тему можно было бы добавить ссылкой в тему «Перенос на другой сервер».

На мой скромный взгляд, безопасность резервных копий по умолчанию также следует улучшить. Хотя пароли и сеансы могут быть захешированы и защищены, в личных сообщениях и подобных данных может содержаться много другой информации, которая должна оставаться конфиденциальной. Особенно отметим, что на нашем форуме сообщества мы поощряем людей использовать личные сообщения для обмена контактными данными и организации продаж или встреч, а не размещать номера телефонов и адреса в публичных местах.

Мой подход к резервному копированию заключается в следующем: войти в экземпляр, создать резервную копию, а затем немедленно зашифровать её с помощью открытого ключа с помощью GPG. Это делает резервную копию бесполезной для любого, у кого нет соответствующего закрытого ключа, который я храню вне сервера и защищаю парольной фразой.

Тем не менее, если секретный ключ для сеансов не меняется, его нужно резервировать только один раз, поэтому достаточно простой процедуры для этого — и, надеюсь, именно это вы описали выше.

Я попробую и посмотрю, смогу ли я создать для вас эту тему :slight_smile:

Очень полезно, @david, спасибо!

Discourse не предлагает функцию «личные сообщения» — эта функция называется «личные сообщения» (Personal Messages). Это различие очень важно: в названии нет намёка на конфиденциальность.

Администраторы уже могут читать каждое личное сообщение на сайте, если не используется шифрование.

Хороший аргумент. Но это не меняет того факта, что участники могут использовать личные сообщения для обмена личными данными или информацией, которую они не хотят делать общедоступной. Поэтому защита этих данных в разумных пределах крайне важна.

Да, нам также приходится доверять администраторам каждого сайта, которым мы пользуемся, даже на таких сайтах, как ProtonMail.

Чуть не по теме… но вас может заинтересовать Discourse Encrypt (deprecated) для по-настоящему «приватных» сообщений. Утечки или кражи зашифрованных личных сообщений не позволят злоумышленнику прочитать их.

(хотя, как вы и заметили, всё ещё предполагается, что администраторам можно доверять)

@david — пожалуйста, проверь следующий пост и, если всё в порядке, раздели его и перемести в howto? (Я не могу создать тему там, и ещё Akismet только что скрыл пост, так что это тоже нужно исправить :blush: )

@david — огромное спасибо за решение этой проблемы и за совет. Надеюсь, это поможет и другим — для нас это действительно облегчение, что мы смогли выполнить миграцию и сохранить сессии :partying_face: