Hardening for SSRF attacks

pull/626/head
utkusen 3 months ago
parent 4486f8040e
commit c2f645c513

@ -1,6 +1,21 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'resolv'
require 'ipaddr'
module DownloadUtils module DownloadUtils
BLOCKED_IP_RANGES = [
IPAddr.new('10.0.0.0/8'),
IPAddr.new('172.16.0.0/12'),
IPAddr.new('192.168.0.0/16'),
IPAddr.new('169.254.0.0/16'),
IPAddr.new('100.64.0.0/10'),
IPAddr.new('127.0.0.0/8'),
IPAddr.new('::1/128'),
IPAddr.new('fc00::/7'),
IPAddr.new('fe80::/10')
].freeze
LOCALHOSTS = Set[ LOCALHOSTS = Set[
'0.0.0.0', '0.0.0.0',
'127.0.0.1', '127.0.0.1',
@ -55,6 +70,27 @@ module DownloadUtils
raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' || raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' ||
[443, nil].exclude?(uri.port) [443, nil].exclude?(uri.port)
raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS) raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS)
validate_resolved_ip!(uri.host)
end
def validate_resolved_ip!(host)
addresses = Resolv.getaddresses(host)
raise UnableToDownload, "Can't resolve host: #{host}" if addresses.empty?
addresses.each do |addr|
if addr.in?(LOCALHOSTS) || private_ip?(addr)
raise UnableToDownload, "Error loading: #{host}. Resolved to a blocked IP: #{addr}"
end
end
end
def private_ip?(ip_str)
ip = IPAddr.new(ip_str)
BLOCKED_IP_RANGES.any? { |range| range.include?(ip) }
rescue IPAddr::InvalidAddressError
false
end end
def conn(validate: Docuseal.multitenant?) def conn(validate: Docuseal.multitenant?)

Loading…
Cancel
Save