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를 사전에 해석(pre-resolve)한 후 git이 해당 사전 해석에서 얻은 IP 주소를 사용하도록 강제합니다. 제 서버에서 이것이 왜 항상 실패하는지 모르겠으므로, 해당 로직을 제거했습니다.

사실 이 로직이 존재하는 이유에 대해 질문이 있습니다. git 자체도 DNS 해석을 수행하는데, 왜 이 로직이 필요한가요? 명확하지 않은 부분인데, 일종의 MITM(인접 공격) 방지 조치인가요?

SSRF(FinalDestination::SSRFDetector에서 언급된 바와 같이)는 **서버 측 요청 위조(Server-Side Request Forgery)**를 의미합니다. 이는 공격자가 서버를 속여, 공격자가 원래 접근할 수 없었던 자원에 접근하게 하는 메커니즘을 가리킵니다.

예를 들어, 인터넷에서 접근할 수 있도록 리버스 프록시를 설정한 사설 네트워크에서 Discourse를 실행하고 있다고 가정해 보겠습니다. 공격자는 사설 네트워크 내부의 IP 주소를 가리키는 링크가 포함된 토픽을 생성할 수 있습니다. 그러면 Discourse의 Onebox 시스템이 해당 URL을 가져와 그 내용을 Onebox로 표시할 수 있습니다.

이를 방지하기 위해 Discourse는 사용자가 제공한 URL이 사설 IP 주소를 가리키지 않는지 먼저 확인한 후에만 해당 URL에 접근합니다.

테마 및 테마 컴포넌트에 사용되는 git 저장소의 경우, 관리자가 직접 지정하므로 중요도가 낮을 수 있다고 볼 수 있지만, Discourse는 여기서 신중함을 기하고 있습니다.

1개의 좋아요

설명해 주셔서 감사합니다. 제 상황에 대한 궁극적인 해결책을 찾았습니다.

제 상황은 다음과 같습니다. WSL(가상 LAN에서 192.168.1.2로 할당됨)을 사용하여 Discourse를 실행하고 있으며, Windows에서 실행되는 프록시(192.168.1.1로 할당됨)를 통해 원격 서버에 연결하도록 구성되어 있습니다.

Discourse가 호스트명으로 원격 서버에 연결하려 할 때, SSRF는 /etc/resolv.conf에 설정된 시스템 DNS를 시도합니다. 그러나 기본적으로 Windows의 vLAN IP 주소(제 경우 192.168.1.1)가 WSL의 유일한 DNS 서버입니다. 하지만 192.168.0.0/16 서브넷은 SSRFDetector에 의해 블랙리스트에 등록되어 있어 DNS 응답조차 받을 수 없습니다. (코드를 대략만 살펴봐서 위 의견이 정확한지 확신은 없습니다.)

192.168.1.1을 Allowed internal hosts 설정 항목에 추가하면 모든 것이 정상적으로 작동합니다. 음, 그러면 Discourse가 환경 변수 HTTP_PROXY와 HTTPS_PROXY의 호스트명을 블랙리스트에 등록하지 않아야 하지 않을까요?