Skip to content

Instantly share code, notes, and snippets.

@tlwr
Created June 10, 2020 11:00
Show Gist options
  • Save tlwr/f88b9ae752203fab0281e50ca0ebe013 to your computer and use it in GitHub Desktop.
Save tlwr/f88b9ae752203fab0281e50ca0ebe013 to your computer and use it in GitHub Desktop.
X-Forwarded-For validation
require 'ipaddr'
def validate(xff_header, allowed_ips, trusted_ips)
request_path = xff_header.split(',').map(&:strip).map { |ip| IPAddr.new ip }
allowed_ranges = allowed_ips.map { |ip| IPAddr.new ip }
trusted_ranges = trusted_ips.map { |ip| IPAddr.new ip }
loop do
return :deny if request_path.empty?
last = request_path.pop
return :allow if allowed_ranges.any? { |r| r.include?(last) }
return :deny unless trusted_ranges.any? { |r| r.include?(last) }
end
end
require 'rspec'
module Helpers
def it_should_allow_the_request
it 'should allow the request' do
expect(validate(xff, allowed_ips, trusted_ips)).to eq(:allow)
end
end
def it_should_deny_the_request
it 'should deny the request' do
expect(validate(xff, allowed_ips, trusted_ips)).to eq(:deny)
end
end
def allowed_ips_are(*ips)
let(:allowed_ips) { ips }
end
def trusted_ips_are(*ips)
let(:trusted_ips) { ips }
end
def xff_header_is(xff)
let(:xff) { xff }
end
end
RSpec.configure { |c| c.extend Helpers }
RSpec.describe 'X-Forwarded-For' do
context 'no IPs are trusted' do
trusted_ips_are
context 'and no IPs are allowed' do
allowed_ips_are
xff_header_is '0.0.0.0'
it_should_deny_the_request
end
context 'and the XFF header does not end with an allowed IP' do
allowed_ips_are '11.11.11.11'
xff_header_is '1.2.3.4, 4.3.2.1'
it_should_deny_the_request
end
context 'and the XFF header ends with an allowed IP' do
allowed_ips_are '11.11.11.11'
xff_header_is '1.2.3.4, 11.11.11.11'
it_should_allow_the_request
end
context 'and the XFF header contains an allowed IP which is not last' do
allowed_ips_are '11.11.11.11'
xff_header_is '1.2.3.4, 11.11.11.11, 5.4.3.2'
it_should_deny_the_request
end
end
context 'IPs are trusted' do
trusted_ips_are '2.3.3.2', '16.16.16.16'
context 'and no IPs are allowed' do
allowed_ips_are
xff_header_is '16.16.16.16'
it_should_deny_the_request
end
context 'and IPs are allowed' do
context 'and the request comes directly from an allowed IP' do
allowed_ips_are '1.2.3.4'
xff_header_is '1.2.3.4'
it_should_allow_the_request
end
context 'and the request via a trusted IP from an allowed IP' do
allowed_ips_are '1.2.3.4'
xff_header_is '1.2.3.4, 16.16.16.16'
it_should_allow_the_request
end
context 'and the request via multiple trusted IPs from an allowed IP' do
allowed_ips_are '1.2.3.4'
xff_header_is '1.2.3.4, 16.16.16.16, 2.3.3.2'
it_should_allow_the_request
end
context 'and the request via an untrusted IP from an allowed IP' do
allowed_ips_are '1.2.3.4'
xff_header_is '1.2.3.4, 17.17.17.17'
it_should_deny_the_request
end
context 'and the request via an untrusted IP and a trusted IP from an allowed IP' do
allowed_ips_are '1.2.3.4'
xff_header_is '1.2.3.4, 17.17.17.17, 2.3.3.2'
it_should_deny_the_request
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment