mirror of
https://github.com/discourse/discourse.git
synced 2025-05-21 18:12:32 +08:00
SECURITY: Expand and improve SSRF Protections (#18815)
See https://github.com/discourse/discourse/security/advisories/GHSA-rcc5-28r3-23rr Co-authored-by: OsamaSayegh <asooomaasoooma90@gmail.com> Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
This commit is contained in:
40
lib/final_destination/http.rb
Normal file
40
lib/final_destination/http.rb
Normal file
@ -0,0 +1,40 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class FinalDestination::HTTP < Net::HTTP
|
||||
def connect
|
||||
original_open_timeout = @open_timeout
|
||||
return super if @ipaddr
|
||||
|
||||
timeout_at = current_time + @open_timeout
|
||||
|
||||
# This iteration through addresses would normally happen in Socket#tcp
|
||||
# We do it here because we're tightly controlling addresses rather than
|
||||
# handing Socket#tcp a hostname
|
||||
ips = FinalDestination::SSRFDetector.lookup_and_filter_ips(@address, timeout: @connect_timeout)
|
||||
|
||||
ips.each_with_index do |ip, index|
|
||||
debug "[FinalDestination] Attempting connection to #{ip}..."
|
||||
self.ipaddr = ip
|
||||
|
||||
remaining_time = timeout_at - current_time
|
||||
if remaining_time <= 0
|
||||
raise Net::OpenTimeout.new("Operation timed out - FinalDestination::HTTP")
|
||||
end
|
||||
|
||||
@open_timeout = remaining_time
|
||||
return super
|
||||
rescue SystemCallError, Net::OpenTimeout => e
|
||||
debug "[FinalDestination] Error connecting to #{ip}... #{e.message}"
|
||||
was_last_attempt = index == ips.length - 1
|
||||
raise if was_last_attempt
|
||||
end
|
||||
ensure
|
||||
@open_timeout = original_open_timeout
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_time
|
||||
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user