Безопасная загрузка

Функция защищённых загрузок (Secure Uploads), добавленная в выпуске Discourse 2.4 в феврале, обеспечивает повышенный уровень безопасности для ВСЕХ загрузок (изображения, видео, аудио, текст, PDF, ZIP-архивы и другие) в рамках экземпляра Discourse.

Требования

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

  • Идентификатор ключа доступа S3 (S3 access key id)
  • Секретный ключ доступа S3 (S3 secret access key)
  • Регион S3
  • Ведро для загрузок S3 (S3 upload bucket)

Также вы должны использовать ведро S3, у которого отсутствует публичная политика доступа (Public bucket policy), и убедиться, что все существующие загрузки имеют ACL с правом публичного чтения (public-read S3 ACL). См. раздел «Включение защищённых загрузок» ниже.

После выполнения этих требований вы можете включить настройку сайта «secure uploads».

Включение защищённых загрузок

:dragon: :warning: ОСТОРОЖНО: ЗДЕСЬ ОБИТАЮТ ДРАКОНЫ :warning: :dragon:

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


Для включения защищённых загрузок выполните следующие шаги:

  1. Убедитесь, что у вас настроены загрузки через S3.
  2. Проверьте, есть ли у вашего ведра S3 публичная политика доступа. Если есть, потребуется дополнительный шаг (шаг 4).
  3. Запустите задачу Rake uploads:sync_s3_acls. Это гарантирует, что все ваши загрузки имеют правильные ACL в S3. Это важно: если выполнить шаг 4 до этого, некоторые загрузки могут стать недоступными на вашем форуме.
  4. Удалите публичную политику доступа из вашего ведра, если она присутствовала на шаге 1.
  5. Включите настройку сайта «secure uploads». При желании включите настройку «предотвращать анонимных пользователей от загрузки файлов», чтобы запретить анонимным пользователям скачивать вложения из публичных тем. Все загрузки, сделанные с этого момента, могут быть помечены как защищённые в зависимости от условий ниже.
  6. Если вы хотите, чтобы все существующие загрузки были проанализированы и, возможно, помечены как защищённые, запустите задачу Rake uploads:secure_upload_analyse_and_update.

:exclamation: Примечание о политике доступа к ведру S3 :exclamation:

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

{
    "Version": "2012-10-17",
    "Id": "ComputedBucketPolicy",
    "Statement": [
        {
            "Sid": "AllowWorldRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*"
        }
    ]
}

Ключевой момент здесь — разрешение * на выполнение действия GetObject, что означает возможность любому пользователю скачивать любые файлы из ведра. Этот статус также отображается в интерфейсе, если политика является публичной:

Эти настройки не следует изменять. На изображении показан идеальный вариант для вкладки «Блокировать публичный доступ»:

Что это делает

После включения функции защищённых загрузок любой файл, загруженный через композер, будет помечен как защищённый или незащищённый в зависимости от следующих критериев:

  • Если у вас включена настройка сайта «требуется вход», все загрузки будут помечены как защищённые, и анонимные пользователи не смогут получить к ним доступ.
  • Если вы загружаете что-либо в рамках личного сообщения, оно будет помечено как защищённое.
  • Если вы загружаете что-либо в теме, находящейся в приватной категории, оно будет помечено как защищённое.

Загрузка в S3 будет иметь приватный ACL, поэтому прямые ссылки на файл в S3 будут возвращать ошибку 403 «доступ запрещён». Любой доступ к защищённым загрузкам будет осуществляться через подписанную URL-адрес S3. Однако для ваших пользователей это будет скрыто: если загрузка защищена, любая ссылка на неё будет осуществляться через URL-адрес Discourse /secure-uploads/.

Разрешения и контроль доступа

URL-адрес /secure-uploads/ определяет, имеет ли текущий пользователь право доступа к медиафайлу, и обслуживает его, если право есть. При создании загрузки пост, в котором она впервые появилась, будет назначен её «постом контроля доступа», и все разрешения будут основываться на этом посте.

  • Если у вас включена настройка сайта «требуется вход», анонимные пользователи всегда будут получать ошибку 404 при попытке доступа к URL.
  • При доступе к медиафайлу, пост контроля доступа которого является личным сообщением, пользователь должен быть участником этой темы личного сообщения, иначе он получит ошибку 403.
  • При доступе к медиафайлу, пост контроля доступа которого находится в теме внутри приватной категории, пользователь должен иметь доступ к этой категории, иначе он получит ошибку 403.

Копирование URL-адресов /secure-uploads/ между постами и темами не рекомендуется, так как у разных пользователей могут быть разные уровни доступа в вашем форуме Discourse. Новые загрузки всегда должны создаваться через композер. Oneboxes и изображения с прямой ссылкой также будут соблюдать правила защищённых загрузок. Настройки сайта, эмодзи и загрузки тем не затрагиваются защищёнными загрузками, так как они должны быть публичными.

:warning: Если пост контроля доступа будет удалён, прикреплённая к нему загрузка станет недоступной. :warning:

Перемещение постов с защищёнными загрузками

Если вы переместите «пост контроля доступа» между разными контекстами безопасности, то прикрепленная к нему загрузка может быть изменена на защищённую или незащищённую. Это ситуации, которые могут изменить уровень безопасности загрузки:

  • Изменение категории темы. Будет выполнена проверка всех постов в теме и обновлён статус безопасности загрузок.
  • Изменение статуса темы с публичной на личное сообщение (и наоборот). Будет выполнено то же самое.
  • Перемещение постов из одной темы в новую или существующую другую тему. Будет выполнено то же самое для целевой темы.

Защищённые загрузки в письмах

Встраивание защищённых изображений в письма включено по умолчанию. Вы можете настроить следующие параметры сайта для дополнительного контроля:

  • secure_uploads_allow_embed_images_in_emails: Отключите это, чтобы скрыть защищённые изображения в письмах.
  • secure_uploads_max_email_embed_image_size_kb: Максимальный размер защищённого изображения, которое будет встроено, по умолчанию 1 МБ, чтобы письмо не стало слишком большим. Максимум — 10 МБ. Работает в связке с email_total_attachment_size_limit_kb.

Защищённые изображения будут добавляться как вложения к письму и встраиваться с использованием формата URL cid:, так как поддержка base64 URL в почтовых клиентах всё ещё нестабильна.

Если у вас не включена настройка secure_uploads_allow_embed_images_in_emails или если изображения превышают ограничения по размеру, вместо защищённых изображений (а также защищённых аудио и видео, которые не встраиваются) вы увидите следующее:

image

Клиенты с хостингом

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

51 лайк
Files/Download Manager For Discourse
Prevent guests from watching images
Register to download
Need log the who downloaded attachments
S3 Bucket objects restricted access policy as per Discourses groups
Signed Google Cloud CDN URLs
Search engines and private messages?
How to make uploads available only to logged-in users
S3 Object Storage for uploads- possible to make private? (and CDN question)
Discourse jumps back 20 posts in post history when navigating to new topic
Discourse jumps back 20 posts in post history when navigating to new topic
Why run UpdatePostUploadsSecureStatus even when secure uploads is disabled?
SSL_connect returned=1 errno=0 peeraddr=162.243.189.2:443 state=error: certificate verify failed (Hostname mismatch)
Understanding Uploads, Images, and Attachments
Capacity planning / Resource requirements
Why you should use Discourse internally for your company/team instead of Slack (4 years use case)
Can't always select any category in composer
S3 Object Storage for uploads- possible to make private? (and CDN question)
Personal Message attachments accessible to unauthenticated users (missing auth check)
Potential Directory Traversal: /uploads/* allows cross-directory file access
S3 Storage with no Public access
Are the images published in the Staff category publicly visible?
Login Only - Does it actually stop all traffic access without login?
为啥我的七牛云s3附件上传成功后,论坛中无法加载出来?
How the media in the posts look like when secure uploads are enabled?
Remove images from emailed reply to forum
Files/Download Manager For Discourse
Topic replies invisible until topic owner decides to reveal them?
Securing private group/category resources
PDF embedding and reading help
Inline PDF Previews
Upload objects to private S3 is not working
Spammers using uploaded images in spam e-mails. Any advice how to resolve?
Secure Media Uploads breaks Category Logos
How to allow downloading images along with other user data (csv) from activity section?
Discourse 2.6.0.beta3 Release Notes
Lock Downloads in discourse
What’s the suggested method to use secure images?
Page Publishing
Errors on Exporting Data from Teams to Self Hosted Discourse on Digital Ocean

Наверное, вокруг этой функции @martin стоит разместить множество предупреждений, так как это :warning: ПРОДВИНУТАЯ вещь, не для слабых :heart:, и мы будем поддерживать её за пределами нашего корпоративного тарифа в ограниченной степени. Приносите свои собственные знания.

9 лайков

Безопасность никогда не предназначалась для аватаров, это не тот сценарий использования, который мы планировали

13 лайков

Предупреждение: Настройка S3-бакета на «Заблокировать весь публичный доступ» является неверной

@genachka @AntiMetaman @Hugh_Roberts @znedw @Thamer

Я собираюсь внести исправления в первое сообщение. После обсуждения с сотрудником нашей инфраструктуры @schleifer я подтвердил, что был неправ, посоветовав включить настройку «Заблокировать весь публичный доступ». Отключите её для вашего S3-бакета, затем выполните команду uploads:sync_s3_acls, чтобы убедиться в правильности ACL, и попробуйте снова с пользовательскими аватарами.

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

{
    "Version": "2012-10-17",
    "Id": "ComputedBucketPolicy",
    "Statement": [
        {
            "Sid": "AllowWorldRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*"
        }
    ]
}

Важный момент здесь заключается в том, что мы разрешаем всем (*) действие GetObject, то есть разрешаем любому пользователю скачивать любые объекты в бакете. Эта метка также будет отображаться, если политика является публичной:

Приношу извинения за это. @AntiMetaman, ни @schleifer, ни я не смогли воспроизвести эту ошибку:

Будет полезно, если вы предоставите дополнительную информацию о вашей настройке S3/AWS.

7 лайков

@martin Спасибо. Проблема была не в той ошибке, а в том, что анонимы не могли получить доступ к странице. Если я установлю загрузочное ведро в режим «приватный», эта ошибка исчезнет, и я смогу загружать файлы. У меня на сайте не включена опция «требуется вход».

У меня изначально никогда не была включена настройка «Заблокировать весь публичный доступ» для параметров ведра. Если вы утверждаете, что анонимы всё ещё должны иметь возможность получать доступ к теме, читать её и просматривать защищённые изображения — тогда я могу попробовать снова. Если добавление защиты к медиафайлам мешает анонимам видеть эти изображения, я предпочту защитить только вложения.

Если это поможет, я использую BackBlaze B2 с BunnyCDN. Мои настройки загрузочного ведра в настоящее время публичные:

4 лайка

В целом да, именно так. Всё, что должно быть приватным, будет иметь установленный приватный ACL и будет недоступно, если не используется предподписанная URL-адреса. Обратите внимание, что политика бакета не является публичной. И да, все настройки «Блокировать публичный доступ» должны быть сняты. Если вас интересует, как мы определяем, является ли загрузка защищённой, все правила описаны здесь: discourse/lib/upload_security.rb at main · discourse/discourse · GitHub и здесь: discourse/app/models/post.rb at main · discourse/discourse · GitHub

К сожалению, я не знаком с BackBlaze. Не уверен, как отображённые настройки соотносятся с политикой бакета. В целом вам не нужна публичная политика бакета, и вы не должны включать «Блокировать весь публичный доступ». Только так мы сможем корректно устанавливать приватные и публичные ACL. Если у вас не требуется вход в систему, то любая загрузка, сделанная в теме, которая не является личной перепиской (PM) или не находится в приватной категории, должна быть публичной и доступной анонимам. Изображения в теме, доступной анонимам, не должны быть защищёнными.

5 лайков

Реализация защищённых медиа несовместима с Backblaze. Поддерживают ли они предподписанные URL-адреса?

1 лайк

@riking

Да, предварительно подписанные URL-адреса поддерживаются: https://help.backblaze.com/hc/en-us/articles/360047815993-Does-the-B2-S3-Compatible-API-support-Pre-Signed-URLs-

@martin

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

4 лайка

@martin, спасибо за уточнение. Могу подтвердить, что при оставлении настройки S3, как на моем скриншоте (публичный доступ, все флажки сняты, как вы и предлагали), кастомные аватары и изображения профиля наконец начали работать, при этом защищенные загрузки тем также функционируют без сбоев. Спасибо!

4 лайка

Я объединил этот PR на этой неделе и добавляю эти детали в исходный пост:


Если вы хотите разрешить встраивание защищённых изображений в электронные письма, вы можете настроить следующие параметры сайта:

  • secure_media_allow_embed_images_in_emails: Если включено, мы будем встраивать защищённые изображения в электронные письма вместо их удаления.
  • secure_media_max_email_embed_image_size_kb: Максимальный размер защищённого изображения, которое мы будем встраивать. По умолчанию — 1 МБ, чтобы письмо не становилось слишком большим. Максимум — 10 МБ. Работает совместно с email_total_attachment_size_limit_kb.

Защищённые изображения будут добавлены как вложения к электронному письму и встроены с использованием формата URL cid:, поскольку поддержка base64 URL в почтовых клиентах всё ещё нестабильна.

Если у вас не включено secure_media_allow_embed_images_in_emails или если изображения превышают ограничения по размеру, то вместо защищённых изображений (а также защищённого аудио и видео, которые не встраиваются) вы увидите следующее:

image

10 лайков

Дополнение к моему предыдущему сообщению; из этого PR:

Теперь безопасное встраивание медиа-изображений включено по умолчанию.

5 лайков

После настройки безопасной загрузки медиафайлов (следуя руководству OP) всё работает хорошо (вложения, изображения…), за исключением загрузок, которые не являются вложениями к темам (например, логотип сайта, аватар профиля). При попытке их загрузить в Discourse появляется всплывающее окно «Access Denied».
Неужели я что-то неправильно настроил?

Пожалуйста, прочитайте тему: ваша проблема обсуждалась несколькими постами выше.

3 лайка

Я внимательно прочитал всё. Пожалуйста, уточните, что именно вы имеете в виду несколькими сообщениями выше. Я не вижу этой проблемы.
Редактирование:
Пытаясь прочитать между строк, я вижу, что эта тема раньше была длиннее, но некоторые ключевые ответы были из неё удалены. Я вижу ссылки на ответы, которых не существует, и упоминания скриншотов, которые не отображаются в теме.
Если я правильно понимаю, рекомендация заключается в том, чтобы настроить бакет S3 так, чтобы он не блокировал никакой публичный доступ. Я просто хочу это подтвердить и спросить: это безопасно?

1 лайк

Верно.

Оригинальное сообщение действительно удалено, но проблема и решение остались.

6 лайков

Я заметил ошибку при использовании защищённых медиафайлов: https://meta.discourse.org/t/knowledge-base-plugin/115288

Ссылки на вложения в базе знаний не открываются (перенаправляют на страницу 404), если не принудительно открыть их в новом окне.

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

Редактирование:
Та же ошибка возникает, когда кто-то копирует ссылку на вложение из одного ответа в другой. Ссылка, естественно, точно такая же, но работает только из исходного ответа, если не принудительно открыть её в новом окне.

1 лайк

Что насчёт защищённых медиафайлов, если S3 не используется?
Сейчас выглядит так, что если у вас есть прямая ссылка на загруженный файл, вы можете скачать его без авторизации. Это похоже на проблему безопасности…

Защищённые медиафайлы требуют использования S3.
Вся эта функция была разработана, чтобы сделать невозможным обмен прямыми ссылками и доступ к ним.

11 лайков

Это отличная функция. Спасибо за её разработку. MinIO, бесплатная замена S3, не поддерживает ACL и никогда не будет. Их аргумент, который является веским, заключается в том, что ACL не являются полезной функцией и негативно влияют на производительность, поскольку требуют второй операции записи. Безопасная загрузка медиафайлов будет работать с Discourse — задача uploads:secure_upload_analyse_and_update завершится ошибкой на последнем шаге, но, похоже, её можно игнорировать. Тем не менее, есть ли какая-либо причина, по которой Discourse вообще должен выполнять вызовы ACL?

3 лайка

Да, потому что бакет S3 является приватным согласно настройкам в оригинальном посте, любые небезопасные загрузки должны иметь ACL, установленный в режим public, а безопасные загрузки будут иметь приватный ACL, чтобы URL S3 можно было получить напрямую. Я не думаю, что у нас есть планы на данный момент изменять то, как это работает; я считаю, что потребуется довольно много работы, чтобы полностью отказаться от использования ACL для замен S3.

7 лайков