open_graph_fetcher 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|