I could not fetch or update any theme component because of that timeout error, finally I figured it out. Removing the following lines starting with - in file <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
These code processes a DNS pre-solution then forces git to use the IP addresses which is obtained from the pre-solution, I do not know why it always failed on my server, so I remove the logic.
In fact, I have a question about its existence, git itself will do a DNS solution, why we need this logic? This is not distinct, a kind of MITM prevention?
SSRF (as mentioned in FinalDestination::SSRFDetector) stands for Server-Side Request Forgery. It refers to a mechanism by which an attacker tricks your server into accessing resources that the attacker would otherwise not be able to access.
For example, imagine you were running Discourse inside a private network with a reverse proxy to allow access from the internet. An attacker could create a topic with a link pointing at an IP address inside your private network. Discourse’s Onebox system might then retrieve that URL and display its contents in a Onebox.
To prevent that, Discourse doesn’t access any user-provided URLs without first checking that they don’t point to private IP addresses.
Arguably this might be less important for git repositories used by themes and theme components, since those are specified by admins, but Discourse is erring on the side of caution here.
Thanks for your explain. I found the ultimate solution for my situation.
My situation: I am using WSL (assigned 192.168.1.2 in the virtual LAN) to run Discourse, and it is configured to connect remote servers through the proxy running on Windows (assigned 192.168.1.1).
When Discourse wants to connect a remote server by a hostname, SSRF will try system DNS set in /etc/resolv.conf, however, in default, Windows’ vLAN IP address (mine is 192.168.1.1) is WSL’s only DNS server. But subnet 192.168.0.0/16 has been blacklisted by SSRFDetector, it can not even acquire DNS answer. (I just skimmed its code, so I do not know whether the opinion above is correct)
By adding 192.168.1.1 into config item Allowed internal hosts, everything continues to work. Umm, maybe Discourse should not blacklist hostname in env var HTTP_PROXY and HTTPS_PROXY?