Sha256: 085903ee2c7176c1c9b0b2bd16ae5f233dad2b0196c1ad38727e5bfdbf191ed5

Contents?: true

Size: 1.99 KB

Versions: 3

Compression:

Stored size: 1.99 KB

Contents

require 'resolv'

module ActionHook
  module Security
    module IPBlocking

      # This is a crucial security feature for sending webhooks. By default, sending webhooks to loopback
      # interfaces or to the private IP space is blocked. In production, it __should__ remain blocked.

      # If the destination host is an IP address, it's a security risk anyway since you can't have TLS.

      # If the destination host is a domain name, we'll attempt to resolve each of the IP addresses that
      # resolve the domain name and block the webhook based on the configuration.

      class BlockedRequestError < StandardError
      end

      class PrivateIPError < StandardError
      end

      def verify_allowed!(configuration, hostname_or_ip)
        return if configuration.allow_all?

        begin
          verify_ip_allowed!(configuration, IPAddr.new(hostname_or_ip))
        rescue IPAddr::InvalidAddressError
          verify_hostname_allowed!(configuration, hostname_or_ip)
        end

      end

      protected

      def verify_ip_allowed!(configuration, ip, host = ip)
        if !configuration.allow_private_ips && (ip.private? || ip.loopback?)
          raise PrivateIPError.new("Host: #{host} IP: #{ip} is private")
        end

        if configuration.blocked_custom_ip_ranges
          found = configuration.blocked_custom_ip_ranges.find{|range| range.include?(ip) }
          if found
            raise BlockedRequestError.new("Host: #{host} IP: #{ip} is part of the blocked range: #{found}")
          end
        end
      end

      def verify_hostname_allowed!(configuration, hostname)
        #TODO: Find out of Resolv looks up all kinds of DNS records and if it can be improved by limiting the DNS record types
        Resolv.each_address(hostname) do |ip|
          begin
            #TODO: Add logging
            verify_ip_allowed!(configuration, IPAddr.new(ip), hostname)
          rescue IPAddr::InvalidAddressError
            #TODO: ADD logging
          end
        end
      end

    end
  end
end

Version data entries

3 entries across 3 versions & 1 rubygems

Version Path
actionhook-1.0.2 lib/actionhook/security/ip_blocking.rb
actionhook-1.0.1 lib/actionhook/security/ip_blocking.rb
actionhook-1.0.0 lib/actionhook/security/ip_blocking.rb