open_graph_fetcher 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -2
- data/examples/fetch.rb +6 -0
- data/lib/open_graph_fetcher/errors.rb +1 -0
- data/lib/open_graph_fetcher/fetcher.rb +10 -1
- data/lib/open_graph_fetcher/version.rb +1 -1
- data/spec/fetcher_spec.rb +11 -5
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c8d1c67970ce91969c7caa437fba256fc1527f46006a10b8576bcd2f52fc774
|
4
|
+
data.tar.gz: 8e994a0fd3b384367c42ab93b73bd9185fa506e1f2af6a702a125bc26314b2a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6d51a0157d6b3088a8f6a8f4bb31243736300fc6bc891ecaafb6b4aa2907236b0b1e45f4e1a22c40c935a4287e3b9ada4509e40c37bbef466c1ce9ae5da2cbe
|
7
|
+
data.tar.gz: 678eab6e764a9ad9fc85c8e09a5b5918409f88a5fc293022c9fa847e3283bd0bc90a37700dd87c36d474566ce13047e7b57a1d8524e635b3ad54952d659ab7bb
|
data/README.md
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
Fetch Open Graph metadata in a safer way.
|
4
4
|
|
5
5
|
- Includes some mitigations for SSRF attacks
|
6
|
-
- Blocks
|
6
|
+
- Blocks the direct usage of IP addresses in URLs
|
7
|
+
- Blocks private and local IP ranges (after DNS resolution)
|
7
8
|
- Avoids TOC/TOU when connecting to the IP
|
8
9
|
- Supports only HTTPS on the standard port (443)
|
9
|
-
- Includes request timeouts
|
10
|
+
- Includes request timeouts (for DNS and HTTP)
|
10
11
|
- Avoids redirects
|
11
12
|
- Allows only text/html responses
|
12
13
|
- Returns only known OG properties and nothing else
|
data/examples/fetch.rb
ADDED
@@ -7,6 +7,7 @@ module OpenGraphFetcher
|
|
7
7
|
class Fetcher
|
8
8
|
OG_PROPERTIES = %w[title type image url description].freeze
|
9
9
|
|
10
|
+
DNS_TIMEOUT = 3
|
10
11
|
OPEN_TIMEOUT = 3
|
11
12
|
READ_TIMEOUT = 3
|
12
13
|
|
@@ -22,6 +23,7 @@ module OpenGraphFetcher
|
|
22
23
|
uri = URI.parse(@url)
|
23
24
|
raise InvalidSchemeError, "Only HTTPS URLs are allowed" unless uri.scheme == "https"
|
24
25
|
raise InvalidPortError, "Only the default HTTPS port (443) is allowed" if uri.port && uri.port != 443
|
26
|
+
raise InvalidHostError, "Using an IP as host is not allowed" if ip_address?(uri.hostname)
|
25
27
|
|
26
28
|
ip_address = resolve_ip(uri)
|
27
29
|
raise PrivateIPError, "Resolved IP address is in a private or reserved range" if private_ip?(ip_address)
|
@@ -36,10 +38,17 @@ module OpenGraphFetcher
|
|
36
38
|
private
|
37
39
|
|
38
40
|
def resolve_ip(uri)
|
39
|
-
Resolv.
|
41
|
+
Resolv::DNS.open do |dns|
|
42
|
+
dns.timeouts = DNS_TIMEOUT
|
43
|
+
dns.getaddress(uri.hostname).to_s
|
44
|
+
end
|
40
45
|
rescue Resolv::ResolvError => e
|
41
46
|
raise IPResolutionError, "Could not resolve IP: #{e.message}"
|
42
47
|
end
|
48
|
+
|
49
|
+
def ip_address?(host)
|
50
|
+
host =~ Resolv::IPv4::Regex || host =~ Resolv::IPv6::Regex
|
51
|
+
end
|
43
52
|
|
44
53
|
def private_ip?(ip)
|
45
54
|
ip_addr = IPAddr.new(ip)
|
data/spec/fetcher_spec.rb
CHANGED
@@ -4,7 +4,7 @@ require 'webmock/rspec'
|
|
4
4
|
RSpec.describe OpenGraphFetcher::Fetcher do
|
5
5
|
|
6
6
|
before do
|
7
|
-
allow(Resolv).to receive(:
|
7
|
+
allow(Resolv::DNS).to receive(:open).and_return("203.0.113.0")
|
8
8
|
end
|
9
9
|
|
10
10
|
describe ".fetch" do
|
@@ -51,20 +51,26 @@ RSpec.describe OpenGraphFetcher::Fetcher do
|
|
51
51
|
expect { OpenGraphFetcher::Fetcher.fetch("https://example.com:8443") }.to raise_error(OpenGraphFetcher::InvalidPortError)
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
context "when given a URL with an IP address" do
|
56
|
+
it "raises an InvalidHostError" do
|
57
|
+
expect { OpenGraphFetcher::Fetcher.fetch("https://203.0.113.0/test") }.to raise_error(OpenGraphFetcher::InvalidHostError)
|
58
|
+
end
|
59
|
+
end
|
54
60
|
|
55
61
|
context "when the IP address cannot be resolved" do
|
56
62
|
it "raises an IPResolutionError with an appropriate error message" do
|
57
|
-
allow(Resolv).to receive(:
|
63
|
+
allow(Resolv::DNS).to receive(:open).and_raise(Resolv::ResolvError, "DNS resolution failed")
|
58
64
|
|
59
|
-
expect { OpenGraphFetcher::Fetcher.fetch("https://nonexistent
|
65
|
+
expect { OpenGraphFetcher::Fetcher.fetch("https://nonexistent.example.com") }.to raise_error(OpenGraphFetcher::IPResolutionError, /Could not resolve IP: DNS resolution failed/)
|
60
66
|
end
|
61
67
|
end
|
62
68
|
|
63
69
|
context "when the resolved IP address is private" do
|
64
70
|
it "raises a PrivateIPError" do
|
65
|
-
allow(Resolv).to receive(:
|
71
|
+
allow(Resolv::DNS).to receive(:open).and_return("10.0.0.1")
|
66
72
|
|
67
|
-
expect { OpenGraphFetcher::Fetcher.fetch("https://
|
73
|
+
expect { OpenGraphFetcher::Fetcher.fetch("https://ssrf.example.com") }.to raise_error(OpenGraphFetcher::PrivateIPError)
|
68
74
|
end
|
69
75
|
end
|
70
76
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: open_graph_fetcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Colli
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- Gemfile
|
64
64
|
- LICENSE
|
65
65
|
- README.md
|
66
|
+
- examples/fetch.rb
|
66
67
|
- lib/open_graph_fetcher.rb
|
67
68
|
- lib/open_graph_fetcher/errors.rb
|
68
69
|
- lib/open_graph_fetcher/fetcher.rb
|