From c0009a5c7f448c2f5d25b1fbe28f9b70065f10d1 Mon Sep 17 00:00:00 2001 From: Max Burkhardt Date: Wed, 17 Jan 2018 10:53:29 -0800 Subject: [PATCH] Add relative redirect support While loading content, a server can send back a `Location` header that just includes a URL path, indicating that the same server should be contacted again, just with a different resource. This was previously unsupported, so this adds the ability to handle these types of redirects. --- CHANGELOG.md | 3 +++ lib/ssrf_filter/ssrf_filter.rb | 2 ++ lib/ssrf_filter/version.rb | 2 +- spec/lib/ssrf_filter_spec.rb | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6275719..4a9914c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.0.4 (1/17/2017) +* Handle relative redirects + ### 1.0.3 (12/4/2017) * Use `frozen_string_literal` pragma in all ruby files * Handle new ruby 2.5 behavior when encountering newlines in header names diff --git a/lib/ssrf_filter/ssrf_filter.rb b/lib/ssrf_filter/ssrf_filter.rb index ab1d7f3..b77101b 100644 --- a/lib/ssrf_filter/ssrf_filter.rb +++ b/lib/ssrf_filter/ssrf_filter.rb @@ -125,6 +125,8 @@ class CRLFInjection < Error case response when ::Net::HTTPRedirection then url = response['location'] + # Handle relative redirects + url = "#{uri.scheme}://#{hostname}:#{uri.port}#{url}" if url.start_with?('/') else return response end diff --git a/lib/ssrf_filter/version.rb b/lib/ssrf_filter/version.rb index 216a45a..faa9368 100644 --- a/lib/ssrf_filter/version.rb +++ b/lib/ssrf_filter/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class SsrfFilter - VERSION = '1.0.3'.freeze + VERSION = '1.0.4'.freeze end diff --git a/spec/lib/ssrf_filter_spec.rb b/spec/lib/ssrf_filter_spec.rb index d100c37..438db29 100644 --- a/spec/lib/ssrf_filter_spec.rb +++ b/spec/lib/ssrf_filter_spec.rb @@ -438,5 +438,20 @@ def inject_custom_trust_store(*certificates) expect(response.code).to eq('200') expect(response.body).to eq('response body') end + + it 'should follow relative redirects and succeed' do + stub_request(:post, "https://#{public_ipv4}/path?key=value").with(headers: {host: 'www.example.com:443'}) + .to_return(status: 301, headers: {location: '/path2?key2=value2'}) + stub_request(:post, "https://#{public_ipv4}/path2?key2=value2") + .with(headers: {host: 'www.example.com:443'}).to_return(status: 200, body: 'response body') + resolver = proc do |hostname| + [{ + 'www.example.com' => public_ipv4 + }[hostname]] + end + response = SsrfFilter.post('https://www.example.com/path?key=value', resolver: resolver) + expect(response.code).to eq('200') + expect(response.body).to eq('response body') + end end end