Created
June 10, 2020 11:00
-
-
Save tlwr/f88b9ae752203fab0281e50ca0ebe013 to your computer and use it in GitHub Desktop.
X-Forwarded-For validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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