unxf 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +0 -5
- data/README +41 -6
- data/lib/unxf.rb +37 -16
- data/test/test_unxf.rb +30 -5
- data/unxf.gemspec +1 -1
- metadata +7 -8
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
data/README
CHANGED
@@ -1,14 +1,49 @@
|
|
1
1
|
= UnXF - Un-X-Forward* the Rack environment
|
2
2
|
|
3
|
-
|
4
|
-
with the
|
5
|
-
|
3
|
+
Rack middleware to remove "HTTP_X_FORWARDED_FOR" in the Rack environment and
|
4
|
+
replace "REMOTE_ADDR" with the value of the original client address.
|
5
|
+
|
6
|
+
This uses the "rpatricia" RubyGem to filter out spoofed requests from
|
7
|
+
clients outside your LAN. The list of trusted address defaults to
|
8
|
+
private LAN addresses defined RFC 1918 and those belonging to localhost.
|
9
|
+
|
10
|
+
This will also read "HTTP_X_FORWARDED_PROTO" and set "rack.url_scheme"
|
11
|
+
to "https" if the "X-Forwarded-Proto" header is set properly and sent
|
12
|
+
from a trusted address chain.
|
13
|
+
|
14
|
+
== Install
|
15
|
+
|
16
|
+
If you use RubyGems:
|
17
|
+
|
18
|
+
gem install unxf
|
19
|
+
|
20
|
+
You will need a C compiler and Ruby development headers to install the
|
21
|
+
"rpatricia" RubyGem if it is not already installed.
|
6
22
|
|
7
23
|
=== Hacking
|
8
24
|
|
25
|
+
You can get the latest source via git from the following locations:
|
26
|
+
|
9
27
|
* git clone git://bogomips.org/unxf.git
|
28
|
+
* git clone git://repo.or.cz/unxf.git (mirror)
|
29
|
+
|
30
|
+
You may browse the code from the web and download the latest snapshot
|
31
|
+
tarballs here:
|
32
|
+
|
33
|
+
* http://bogomips.org/unxf.git (cgit)
|
34
|
+
* http://repo.or.cz/w/unxf.git (gitweb)
|
35
|
+
|
36
|
+
Inline patches (from "git format-patch") to the
|
37
|
+
{mailing list}[mailto:unxf@librelist.org] are
|
38
|
+
preferred because they allow code review and comments in the reply to
|
39
|
+
the patch.
|
40
|
+
|
41
|
+
We will adhere to mostly the same conventions for patch submissions as
|
42
|
+
git itself. See the Documentation/SubmittingPatches document
|
43
|
+
distributed with git on on patch submission guidelines to follow. Just
|
44
|
+
don't email the git mailing list or maintainer with unxf patches.
|
10
45
|
|
11
|
-
|
46
|
+
== Contact
|
12
47
|
|
13
|
-
|
14
|
-
|
48
|
+
All feedback (bug reports, user/development discussion, patches, pull
|
49
|
+
requests) go to the mailing list: mailto:unxf@librelist.org
|
data/lib/unxf.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'rpatricia'
|
3
3
|
|
4
|
+
# Rack middleware to remove "HTTP_X_FORWARDED_FOR" in the Rack environment and
|
5
|
+
# replace "REMOTE_ADDR" with the value of the original client address.
|
4
6
|
class UnXF
|
5
7
|
# :stopdoc:
|
6
8
|
# reduce garbage overhead by using constant strings
|
@@ -17,6 +19,19 @@ class UnXF
|
|
17
19
|
# localhost addresses (127.0.0.0/8)
|
18
20
|
LOCALHOST = %w(127.0.0.0/8)
|
19
21
|
|
22
|
+
# In your Rack config.ru:
|
23
|
+
#
|
24
|
+
# use UnXF
|
25
|
+
#
|
26
|
+
# If you do not want to trust any hosts other than "0.6.6.6",
|
27
|
+
# you may only specify one host to trust:
|
28
|
+
#
|
29
|
+
# use UnXF, "0.6.6.6"
|
30
|
+
#
|
31
|
+
# If you want to trust "0.6.6.6" in addition to the default set of hosts:
|
32
|
+
#
|
33
|
+
# use UnXF, [ :RFC_1918, :LOCALHOST, "0.6.6.6" ]
|
34
|
+
#
|
20
35
|
def initialize(app, trusted = [:RFC_1918, :LOCALHOST])
|
21
36
|
@app = app
|
22
37
|
@trusted = Patricia.new
|
@@ -26,7 +41,15 @@ class UnXF
|
|
26
41
|
end
|
27
42
|
end
|
28
43
|
|
29
|
-
|
44
|
+
# Rack entry point
|
45
|
+
def call(env) # :nodoc:
|
46
|
+
unxf!(env) || @app.call(env)
|
47
|
+
end
|
48
|
+
|
49
|
+
# returns +nil+ on success and a Rack response triplet on failure
|
50
|
+
# This allows existing applications to use UnXF without putting it
|
51
|
+
# into the middleware stack (to avoid increasing stack depth and GC time)
|
52
|
+
def unxf!(env)
|
30
53
|
if xff_str = env.delete(HTTP_X_FORWARDED_FOR)
|
31
54
|
xff = xff_str.split(/\s*,\s*/)
|
32
55
|
addr = env[REMOTE_ADDR]
|
@@ -35,33 +58,31 @@ class UnXF
|
|
35
58
|
addr = tmp
|
36
59
|
end
|
37
60
|
rescue ArgumentError
|
38
|
-
return
|
61
|
+
return on_broken_addr(env, xff_str)
|
39
62
|
end
|
40
63
|
|
41
|
-
env[REMOTE_ADDR] = addr
|
42
|
-
|
43
64
|
# it's stupid to have https at any point other than the first
|
44
65
|
# proxy in the chain, so we don't support that
|
45
66
|
if xff.empty?
|
67
|
+
env[REMOTE_ADDR] = addr
|
46
68
|
env.delete(HTTP_X_FORWARDED_PROTO) =~ /\Ahttps\b/ and
|
47
69
|
env[RACK_URL_SCHEME] = HTTPS
|
48
70
|
else
|
49
|
-
return
|
71
|
+
return on_untrusted_addr(env, xff_str)
|
50
72
|
end
|
51
73
|
end
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# Our default action on a broken address is to just fall back to calling
|
78
|
+
# the app without modifying the env
|
79
|
+
def on_broken_addr(env, xff_str)
|
52
80
|
@app.call(env)
|
53
81
|
end
|
54
82
|
|
55
|
-
# Our default action on
|
56
|
-
# the
|
57
|
-
|
58
|
-
|
59
|
-
# be sure to inspect xff_str to escape it, control characters may be
|
60
|
-
# present in the HTTP headers may appear in the header value and
|
61
|
-
# used to exploit anyone who opens the log file. nginx doesn't
|
62
|
-
# filter/reject control characters, nor does Mongrel...
|
63
|
-
env["rack.logger"].error(
|
64
|
-
"bad XFF #{xff_str.inspect} from #{env[REMOTE_ADDR]}")
|
65
|
-
[ 400, [ %w(Content-Length 0), %w(Content-Type text/html) ], [] ]
|
83
|
+
# Our default action on an untrusted address is to just fall back to calling
|
84
|
+
# the app without modifying the env
|
85
|
+
def on_untrusted_addr(env, xff_str)
|
86
|
+
@app.call(env)
|
66
87
|
end
|
67
88
|
end
|
data/test/test_unxf.rb
CHANGED
@@ -46,7 +46,8 @@ class TestUnXF < Test::Unit::TestCase
|
|
46
46
|
"REMOTE_ADDR" => "227.0.0.1",
|
47
47
|
}
|
48
48
|
r = req.get("http://example.com/", @req.merge(env))
|
49
|
-
assert_equal
|
49
|
+
assert_equal "227.0.0.1", @env["REMOTE_ADDR"]
|
50
|
+
assert_equal r.status.to_i, 200
|
50
51
|
end
|
51
52
|
|
52
53
|
def test_trusted_chain
|
@@ -68,8 +69,8 @@ class TestUnXF < Test::Unit::TestCase
|
|
68
69
|
"REMOTE_ADDR" => "127.0.0.1",
|
69
70
|
}
|
70
71
|
r = req.get("http://example.com/", @req.merge(env))
|
71
|
-
assert_equal
|
72
|
-
|
72
|
+
assert_equal "127.0.0.1", @env["REMOTE_ADDR"]
|
73
|
+
assert_equal r.status.to_i, 200
|
73
74
|
end
|
74
75
|
|
75
76
|
def test_spoofed_null_safe
|
@@ -79,7 +80,31 @@ class TestUnXF < Test::Unit::TestCase
|
|
79
80
|
"REMOTE_ADDR" => "127.0.0.1",
|
80
81
|
}
|
81
82
|
r = req.get("http://example.com/", @req.merge(env))
|
82
|
-
assert_equal
|
83
|
-
|
83
|
+
assert_equal "127.0.0.1", @env["REMOTE_ADDR"]
|
84
|
+
assert_equal r.status.to_i, 200
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_more_trust
|
88
|
+
req = Rack::MockRequest.new(UnXF.new(@app, [ :LOCALHOST, "0.6.6.6" ]))
|
89
|
+
env = {
|
90
|
+
"HTTP_X_FORWARDED_FOR" => "1.6.6.6,0.6.6.6",
|
91
|
+
"REMOTE_ADDR" => "127.0.0.1",
|
92
|
+
}
|
93
|
+
r = req.get("http://example.com/", @req.merge(env))
|
94
|
+
assert_equal r.status.to_i, 200
|
95
|
+
assert_equal "1.6.6.6", @env["REMOTE_ADDR"]
|
96
|
+
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_one_trusted
|
100
|
+
req = Rack::MockRequest.new(UnXF.new(@app, "0.6.6.6"))
|
101
|
+
env = {
|
102
|
+
"HTTP_X_FORWARDED_FOR" => "1.6.6.6",
|
103
|
+
"REMOTE_ADDR" => "0.6.6.6",
|
104
|
+
}
|
105
|
+
r = req.get("http://example.com/", @req.merge(env))
|
106
|
+
assert_equal r.status.to_i, 200
|
107
|
+
assert_equal "1.6.6.6", @env["REMOTE_ADDR"]
|
108
|
+
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
84
109
|
end
|
85
110
|
end
|
data/unxf.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.test_files = test_files
|
22
22
|
s.add_dependency('rack', '~> 1.1')
|
23
23
|
s.add_development_dependency('wrongdoc', '~> 1.5')
|
24
|
-
s.
|
24
|
+
s.add_dependency('rpatricia', '~> 0.07')
|
25
25
|
|
26
26
|
# s.license = %w(GPL) # disabled for compatibility with older RubyGems
|
27
27
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unxf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
version:
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- UnXF hackers
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-26 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rack
|
@@ -60,12 +60,11 @@ dependencies:
|
|
60
60
|
- 0
|
61
61
|
- 7
|
62
62
|
version: "0.07"
|
63
|
-
type: :
|
63
|
+
type: :runtime
|
64
64
|
version_requirements: *id003
|
65
65
|
description: |-
|
66
|
-
|
67
|
-
with the
|
68
|
-
chain is provided).
|
66
|
+
Rack middleware to remove "HTTP_X_FORWARDED_FOR" in the Rack environment and
|
67
|
+
replace "REMOTE_ADDR" with the value of the original client address.
|
69
68
|
email: unxf@librelist.org
|
70
69
|
executables: []
|
71
70
|
|