Миниатюры чата обходят s3_cdn_url и используют прямые URL-адреса S3-бакетов

Я недавно настроил бакет для загрузки в Cloudflare R2, и миниатюры изображений в чате перестали отображаться. Я провёл расследование, быстро исправил конфигурацию и наткнулся на эту тему: Cloudflare R2 Image URL Display Issue: Detailed Explanation and Fix. В итоге я изучил другие конфигурации бакетов для загрузки в S3 и понял, что проблема не специфична для Cloudflare.


Описание

Когда для загрузки настроено внешнее хранилище S3 или совместимое с ним, миниатюры изображений в чате обходят CDN и загружаются напрямую по URL бакета.

Для защищённых внешних бакетов, совместимых с S3 (например, Cloudflare R2), миниатюры в чате ломаются и не отображаются.

Суть проблемы заключается в том, что сериализатор чата не применяет настройку s3_cdn_url к миниатюрам. Вместо того чтобы перенаправлять изображение через настроенный CDN, он передаёт в полезную нагрузку браузера «сырой» внутренний URL бакета S3.

Шаги для воспроизведения

Это можно воспроизвести на Meta и других сайтах, использующих бакеты для загрузки в S3:

  1. Опубликуйте изображение в чате или канале.
  2. Проверьте URL миниатюры изображения в консоли.
  3. Нажмите на изображение, чтобы открыть оригинал большего размера, и проверьте URL.
  4. Сравните его с URL миниатюры.

Вот пример из чата Meta:

URL миниатюры: напрямую из бакета

https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/meta/optimized/4X/4/7/9/479815360e0e6e0cd9f4ba565891776e84aea532_2_375x500.jpeg

URL оригинала: через CDN

https://global.discourse-cdn.com/meta/original/4X/4/7/9/479815360e0e6e0cd9f4ba565891776e84aea532.jpeg

В консоли HTML для миниатюры <img... содержит атрибут data-large-src с URL CDN CloudFront, а атрибут src — URL бакета AWS.

скриншот

Влияние:

  • Для хранилищ, совместимых с S3 (например, Cloudflare R2), которые по умолчанию защищены и блокируют неаутентифицированный доступ к конечным точкам сырых бакетов, миниатюры изображений в чате (оптимизированные) не работают.
  • Утечка трафика (и денег) для AWS и других хранилищ, совместимых с S3, которые позволяют доступ к конечным точкам сырых бакетов, так как чат полностью обходит CDN; это приводит к оплате прямых сборов за исходящий трафик S3 за весь трафик миниатюр чата.
  • Утечка инфраструктуры: «сырые» URL бэкенд-хранилищ (включая внутренние имена бакетов, а иногда и идентификаторы аккаунтов) раскрываются в полезных нагрузках JSON на стороне клиента.

PR:

Я подготовил PR для исправления этой проблемы здесь:

https://github.com/discourse/discourse/pull/40419

Похоже, что Сэм добавил метод getURLWithCDN в предпросмотр композера чата — однако, я не уверен, что он работает в потоке чата?

Мне интересно, могло ли исправление в композере не работать для некоторых конфигураций S3 из-за того, что getURLWithCDN падает при несовпадении протоколов (// против https://)? В любом случае, вышеуказанный PR просто расширяет работу Сэма, добавляя обёртки для потока и делая решение независимым от протокола.

Временное решение:

Прежде чем я понял, что проблема не только в Cloudflare, я создал лёгкий компонент темы. Он перехватывает «сырые» домены S3 в DOM чата и заменяет их на правильный домен CDN до того, как браузер попытается загрузить их. Это правильно маршрутизирует трафик и устраняет утечку трафика. Я адаптировал его для работы с любым хранилищем, совместимым с S3. Достаточно всего двух настроек: Raw S3 bucket URL (Сырой URL бакета S3) и S3 CDN URL (URL CDN S3).

https://github.com/Lillinator/chat-s3-thumbnails-fix

(не знаю, почему однобоковые ссылки GitHub здесь не работают) Исправлено сейчас

5 лайков

Скорее всего, связано с переездом сайта… Я только что перекомпилировал.

2 лайка

Привет, уже ли слит этот PR?

Спасибо

2 лайка

сейчас ждёт проверки от человека после того, как мой приятель discourse-triage-bot исправил некоторые тесты :slight_smile:

https://github.com/discourse/discourse/pull/40419#issuecomment-4683409099

5 лайков

похоже, это уже объединено.

4 лайка

открыто по запросу автора

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

в отличие от стандартных изображений в постах (которые можно исправить с помощью rake posts:rebake), пользовательские эмодзи в чате передаются на фронтенд динамически через /site.json.

если ваша база данных содержит URL-адреса S3, в которых отсутствует протокол (например, //bucket.endpoint...) или используется виртуальный хост, который не полностью соответствует переменным среды в вашем app.yml, внутренний CDN-реплейсер Discourse молча терпит неудачу. сырой URL-адрес бакета передается в браузер, что приводит к поломке пользовательских эмодзи в чате.

как исправить:

чтобы исправить это навсегда, вам нужно принудительно переназначить сырые URL-адреса бакета на URL-адрес вашего CDN в базе данных, а затем очистить кэш сайта, чтобы /site.json перегенерировался.

1. войдите в контейнер:

войдите на свой сервер через ssh и войдите в контейнер Discourse (обычно app или web_only, если у вас двухконтейнерная настройка).

cd /var/discourse
./launcher enter app

2. переназначьте URL-адреса:

запустите встроенный инструмент Discourse remap. вы должны запустить его дважды, чтобы поймать как вариант https://, так и безпротокольный вариант //, который иногда оставляет скрипт миграции.

замените заполнители на ваши фактические URL-адреса сырого бакета и фактический URL-адрес CDN:

# исправьте стандартные URL-адреса https://
discourse remap "https://<your-bucket>.<your-endpoint>.com" "https://cdn.your-domain.com"

# исправьте безпротокольные URL-адреса // (это тот, который обычно ломает пользовательские эмодзи)
discourse remap "//<your-bucket>.<your-endpoint>.com" "https://cdn.your-domain.com"

3. очистите кэш

поскольку /site.json сильно кэшируется, вам необходимо очистить кэш rails, чтобы принудительно заставить форум обслуживать новые URL-адреса:

откройте консоль rails:

rails c

запустите эти команды:

Rails.cache.clear
Site.clear_cache
exit

4. обновите страницу

жестко обновите ваш браузер (и отключите обходное решение темы-компонента, если вы все еще используете его). пользовательские эмодзи в чате теперь должны быть исправлены и правильно загружаться через CDN.

3 лайка

Привет, Лилли! Большое спасибо за твою отличную работу. После двух переназначений теперь корректно работают мои старые загрузки и миниатюры. До этого не работали даже изображения на странице “/admin/config/customize/themes”. Сейчас всё исправлено. Замечательно!

Спасибо!

1 лайк