Module: Verikloak::SafeUrl Private

Defined in:
lib/verikloak/safe_url.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Shared URL normalization and SSRF-protection helpers used by Discovery and JwksCache. Callers keep their own error classes and codes; this module only answers questions about URLs.

NOTE: The private-IP check resolves the hostname at validation time, while the HTTP client resolves it again at connection time. A DNS rebinding attack (short-TTL records) can therefore pass validation and still connect to a private address. See SECURITY.md ("Known limitations").

Class Method Summary collapse

Class Method Details

.insecure_http?(url, allow_http:) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Whether the URL uses plain HTTP while HTTP is not allowed.

Parameters:

  • url (String)

    Normalized URL string.

  • allow_http (Boolean)

Returns:

  • (Boolean)


52
53
54
# File 'lib/verikloak/safe_url.rb', line 52

def insecure_http?(url, allow_http:)
  !allow_http && !url.start_with?('https://')
end

.normalize(url) ⇒ String?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Strips surrounding whitespace and verifies the value is an HTTP(S) URL.

Parameters:

  • url (Object)

    Candidate URL (any type).

Returns:

  • (String, nil)

    The stripped URL string, or nil when the value is not a String or does not start with http:// or https://.



40
41
42
43
44
45
# File 'lib/verikloak/safe_url.rb', line 40

def normalize(url)
  return nil unless url.is_a?(String)

  normalized = url.strip
  normalized.match?(%r{\Ahttps?://}) ? normalized : nil
end

.private_address?(address) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Whether a single address string falls within PRIVATE_IP_RANGES.

Parameters:

  • address (String)

Returns:

  • (Boolean)


75
76
77
78
79
80
81
# File 'lib/verikloak/safe_url.rb', line 75

def private_address?(address)
  ip = IPAddr.new(address)
  ip = ip.native if ip.ipv4_mapped?
  PRIVATE_IP_RANGES.any? { |range| range.include?(ip) }
rescue IPAddr::InvalidAddressError
  false
end

.resolves_to_private_ip?(host) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Whether the hostname resolves to at least one private/internal address.

IPv4-mapped IPv6 addresses (e.g. ::ffff:127.0.0.1) are normalised to their native IPv4 form before comparison. Addresses that cannot be parsed are ignored (the HTTP client will surface any real connection error).

Parameters:

  • host (String, nil)

    Hostname or IP literal.

Returns:

  • (Boolean)


65
66
67
68
69
# File 'lib/verikloak/safe_url.rb', line 65

def resolves_to_private_ip?(host)
  return false if host.nil? || host.to_s.empty?

  Resolv.getaddresses(host).any? { |addr| private_address?(addr) }
end