Block loopback addresses in UrlBlocker

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/51128
This commit is contained in:
Stan Hu 2018-09-05 21:41:59 -07:00
parent ab22dae917
commit b1d04cf9d5
3 changed files with 33 additions and 1 deletions

View file

@ -0,0 +1,5 @@
---
title: Block loopback addresses in UrlBlocker
merge_request:
author:
type: security

View file

@ -30,6 +30,7 @@ module Gitlab
end end
validate_localhost!(addrs_info) unless allow_localhost validate_localhost!(addrs_info) unless allow_localhost
validate_loopback!(addrs_info) unless allow_localhost
validate_local_network!(addrs_info) unless allow_local_network validate_local_network!(addrs_info) unless allow_local_network
validate_link_local!(addrs_info) unless allow_local_network validate_link_local!(addrs_info) unless allow_local_network
@ -84,6 +85,12 @@ module Gitlab
raise BlockedUrlError, "Requests to localhost are not allowed" raise BlockedUrlError, "Requests to localhost are not allowed"
end end
def validate_loopback!(addrs_info)
return unless addrs_info.any? { |addr| addr.ipv4_loopback? || addr.ipv6_loopback? }
raise BlockedUrlError, "Requests to loopback addresses are not allowed"
end
def validate_local_network!(addrs_info) def validate_local_network!(addrs_info)
return unless addrs_info.any? { |addr| addr.ipv4_private? || addr.ipv6_sitelocal? } return unless addrs_info.any? { |addr| addr.ipv4_private? || addr.ipv6_sitelocal? }

View file

@ -29,6 +29,16 @@ describe Gitlab::UrlBlocker do
expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', protocols: ['http'])).to be true expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', protocols: ['http'])).to be true
end end
it 'returns true for localhost IPs' do
expect(described_class.blocked_url?('https://0.0.0.0/foo/foo.git')).to be true
expect(described_class.blocked_url?('https://[::1]/foo/foo.git')).to be true
expect(described_class.blocked_url?('https://127.0.0.1/foo/foo.git')).to be true
end
it 'returns true for loopback IP' do
expect(described_class.blocked_url?('https://127.0.0.2/foo/foo.git')).to be true
end
it 'returns true for alternative version of 127.0.0.1 (0177.1)' do it 'returns true for alternative version of 127.0.0.1 (0177.1)' do
expect(described_class.blocked_url?('https://0177.1:65535/foo/foo.git')).to be true expect(described_class.blocked_url?('https://0177.1:65535/foo/foo.git')).to be true
end end
@ -84,6 +94,16 @@ describe Gitlab::UrlBlocker do
end end
end end
it 'allows localhost endpoints' do
expect(described_class).not_to be_blocked_url('http://0.0.0.0', allow_localhost: true)
expect(described_class).not_to be_blocked_url('http://localhost', allow_localhost: true)
expect(described_class).not_to be_blocked_url('http://127.0.0.1', allow_localhost: true)
end
it 'allows loopback endpoints' do
expect(described_class).not_to be_blocked_url('http://127.0.0.2', allow_localhost: true)
end
it 'allows IPv4 link-local endpoints' do it 'allows IPv4 link-local endpoints' do
expect(described_class).not_to be_blocked_url('http://169.254.169.254') expect(described_class).not_to be_blocked_url('http://169.254.169.254')
expect(described_class).not_to be_blocked_url('http://169.254.168.100') expect(described_class).not_to be_blocked_url('http://169.254.168.100')
@ -122,7 +142,7 @@ describe Gitlab::UrlBlocker do
end end
def stub_domain_resolv(domain, ip) def stub_domain_resolv(domain, ip)
allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([double(ip_address: ip, ipv4_private?: true, ipv6_link_local?: false)]) allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([double(ip_address: ip, ipv4_private?: true, ipv6_link_local?: false, ipv4_loopback?: false, ipv6_loopback?: false)])
end end
def unstub_domain_resolv def unstub_domain_resolv