Решена ошибка тайм-аута при загрузке компонентов темы путём отключения предварительного разрешения DNS

Продолжение обсуждения из Recent updates seemed to stop rake task themes:update to use a proxy server:

Из-за этой ошибки тайм-аута я не мог получить или обновить ни один компонент темы, но в конце концов разобрался. Удалите следующие строки, начинающиеся с -, в файле <Discourse>/lib/theme_store/git_importer.rb:

  def clone_http!
    uri = redirected_uri

    raise_import_error! if %w[http https].exclude?(@uri.scheme)

-    addresses = FinalDestination::SSRFDetector.lookup_and_filter_ips(uri.host)

-    raise_import_error! if addresses.empty?

    env = { "GIT_TERMINAL_PROMPT" => "0" }

    args =
      clone_args(
        uri.to_s,
-        "http.followRedirects" => "false",
-        "http.curloptResolve" => "#{uri.host}:#{uri.port}:#{addresses.join(",")}",
      )

    begin
      Discourse::Utils.execute_command(env, *args, timeout: COMMAND_TIMEOUT_SECONDS)
    rescue RuntimeError
      raise_import_error!
    end
  end

Этот код выполняет предварительное разрешение DNS, а затем принудительно заставляет git использовать IP-адреса, полученные в результате этого разрешения. Не знаю, почему это постоянно не работало на моём сервере, поэтому я убрал эту логику.

Кстати, у меня есть вопрос насчёт её необходимости: сам git выполняет разрешение DNS, зачем тогда нужна эта логика? Это что-то вроде защиты от MITM? Не совсем понятно.

SSRF (как упоминается в FinalDestination::SSRFDetector) означает подделка запросов с сервера (Server-Side Request Forgery). Это механизм, с помощью которого злоумышленник обманом заставляет ваш сервер получать доступ к ресурсам, к которым он иначе не смог бы получить доступ.

Например, представьте, что вы запускаете Discourse в частной сети с обратным прокси-сервером для доступа из интернета. Злоумышленник может создать тему со ссылкой, указывающей на IP-адрес внутри вашей частной сети. Система Onebox в Discourse может затем извлечь этот URL и отобразить его содержимое в блоке Onebox.

Чтобы предотвратить это, Discourse не обращается к любым URL, предоставленным пользователем, не проверив предварительно, что они не указывают на частные IP-адреса.

Возможно, это менее важно для репозиториев Git, используемых темами и компонентами тем, поскольку они указываются администраторами, но Discourse в данном случае предпочитает перестраховаться.

1 лайк

Спасибо за объяснение. Я нашел окончательное решение для своей ситуации.

Моя ситуация: я использую WSL (в виртуальной LAN ему назначен адрес 192.168.1.2) для запуска Discourse, и он настроен на подключение к удаленным серверам через прокси, работающий в Windows (ему назначен адрес 192.168.1.1).

Когда Discourse пытается подключиться к удаленному серверу по имени хоста, SSRF обращается к системному DNS, указанному в /etc/resolv.conf. Однако по умолчанию IP-адрес виртуальной LAN Windows (в моем случае 192.168.1.1) является единственным DNS-сервером WSL. Но подсеть 192.168.0.0/16 была заблокирована SSRFDetector, поэтому даже ответ DNS получить не удается. (Я лишь бегло просмотрел его код, поэтому не уверен, что мое предположение верно.)

Добавив 192.168.1.1 в параметр конфигурации Allowed internal hosts, я восстановил работоспособность всего. Хм, возможно, Discourse не должен блокировать имена хостов в переменных окружения HTTP_PROXY и HTTPS_PROXY?