rack-protection-monkey 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/License +20 -0
- data/README.md +90 -0
- data/Rakefile +48 -0
- data/lib/rack-protection.rb +1 -0
- data/lib/rack/protection.rb +40 -0
- data/lib/rack/protection/authenticity_token.rb +31 -0
- data/lib/rack/protection/base.rb +121 -0
- data/lib/rack/protection/escaped_params.rb +87 -0
- data/lib/rack/protection/form_token.rb +23 -0
- data/lib/rack/protection/frame_options.rb +37 -0
- data/lib/rack/protection/http_origin.rb +34 -0
- data/lib/rack/protection/ip_spoofing.rb +23 -0
- data/lib/rack/protection/json_csrf.rb +35 -0
- data/lib/rack/protection/path_traversal.rb +47 -0
- data/lib/rack/protection/remote_referrer.rb +20 -0
- data/lib/rack/protection/remote_token.rb +22 -0
- data/lib/rack/protection/session_hijacking.rb +36 -0
- data/lib/rack/protection/version.rb +16 -0
- data/lib/rack/protection/xss_header.rb +25 -0
- data/rack-protection.gemspec +123 -0
- data/spec/lib/rack/protection/authenticity_token_spec.rb +46 -0
- data/spec/lib/rack/protection/base_spec.rb +38 -0
- data/spec/lib/rack/protection/escaped_params_spec.rb +41 -0
- data/spec/lib/rack/protection/form_token_spec.rb +31 -0
- data/spec/lib/rack/protection/frame_options_spec.rb +37 -0
- data/spec/lib/rack/protection/http_origin_spec.rb +40 -0
- data/spec/lib/rack/protection/ip_spoofing_spec.rb +33 -0
- data/spec/lib/rack/protection/json_csrf_spec.rb +56 -0
- data/spec/lib/rack/protection/path_traversal_spec.rb +39 -0
- data/spec/lib/rack/protection/protection_spec.rb +103 -0
- data/spec/lib/rack/protection/remote_referrer_spec.rb +29 -0
- data/spec/lib/rack/protection/remote_token_spec.rb +40 -0
- data/spec/lib/rack/protection/session_hijacking_spec.rb +53 -0
- data/spec/lib/rack/protection/xss_header_spec.rb +54 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/support/dummy_app.rb +7 -0
- data/spec/support/not_implemented_as_pending.rb +23 -0
- data/spec/support/rack_monkey_patches.rb +21 -0
- data/spec/support/shared_examples.rb +65 -0
- data/spec/support/spec_helpers.rb +36 -0
- metadata +180 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: CSRF
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
9
|
+
#
|
10
|
+
# Only accepts submitted forms if a given access token matches the token
|
11
|
+
# included in the session. Does not expect such a token from Ajax request.
|
12
|
+
#
|
13
|
+
# This middleware is not used when using the Rack::Protection collection,
|
14
|
+
# since it might be a security issue, depending on your application
|
15
|
+
#
|
16
|
+
# Compatible with Rails and rack-csrf.
|
17
|
+
class FormToken < AuthenticityToken
|
18
|
+
def accepts?(env)
|
19
|
+
env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" or super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: Clickjacking
|
7
|
+
# Supported browsers:: Internet Explorer 8, Firefox 3.6.9, Opera 10.50,
|
8
|
+
# Safari 4.0, Chrome 4.1.249.1042 and later
|
9
|
+
# More infos:: https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header
|
10
|
+
#
|
11
|
+
# Sets X-Frame-Options header to tell the browser avoid embedding the page
|
12
|
+
# in a frame.
|
13
|
+
#
|
14
|
+
# Options:
|
15
|
+
#
|
16
|
+
# frame_options:: Defines who should be allowed to embed the page in a
|
17
|
+
# frame. Use :deny to forbid any embedding, :sameorigin
|
18
|
+
# to allow embedding from the same origin (default).
|
19
|
+
class FrameOptions < Base
|
20
|
+
default_options :frame_options => :sameorigin
|
21
|
+
|
22
|
+
def frame_options
|
23
|
+
@frame_options ||= begin
|
24
|
+
frame_options = options[:frame_options]
|
25
|
+
frame_options = options[:frame_options].to_s.upcase unless frame_options.respond_to? :to_str
|
26
|
+
frame_options.to_str
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env)
|
31
|
+
status, headers, body = @app.call(env)
|
32
|
+
headers['X-Frame-Options'] ||= frame_options if html? headers
|
33
|
+
[status, headers, body]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: CSRF
|
7
|
+
# Supported browsers:: Google Chrome 2, Safari 4 and later
|
8
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
9
|
+
# http://tools.ietf.org/html/draft-abarth-origin
|
10
|
+
#
|
11
|
+
# Does not accept unsafe HTTP requests when value of Origin HTTP request header
|
12
|
+
# does not match default or whitelisted URIs.
|
13
|
+
class HttpOrigin < Base
|
14
|
+
DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 }
|
15
|
+
default_reaction :deny
|
16
|
+
|
17
|
+
def base_url(env)
|
18
|
+
request = Rack::Request.new(env)
|
19
|
+
port = ":#{request.port}" unless request.port == DEFAULT_PORTS[request.scheme]
|
20
|
+
"#{request.scheme}://#{request.host}#{port}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def accepts?(env)
|
24
|
+
origin = env['HTTP_ORIGIN']
|
25
|
+
|
26
|
+
return true if safe? env
|
27
|
+
return true unless origin && origin != 'null'
|
28
|
+
return true if base_url(env) == origin
|
29
|
+
Array(options[:origin_whitelist]).include? origin
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: IP spoofing
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://blog.c22.cc/2011/04/22/surveymonkey-ip-spoofing/
|
9
|
+
#
|
10
|
+
# Detect (some) IP spoofing attacks.
|
11
|
+
class IPSpoofing < Base
|
12
|
+
default_reaction :deny
|
13
|
+
|
14
|
+
def accepts?(env)
|
15
|
+
return true unless env.include? 'HTTP_X_FORWARDED_FOR'
|
16
|
+
ips = env['HTTP_X_FORWARDED_FOR'].split(/\s*,\s*/)
|
17
|
+
return false if env.include? 'HTTP_CLIENT_IP' and not ips.include? env['HTTP_CLIENT_IP']
|
18
|
+
return false if env.include? 'HTTP_X_REAL_IP' and not ips.include? env['HTTP_X_REAL_IP']
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: CSRF
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://flask.pocoo.org/docs/security/#json-security
|
9
|
+
#
|
10
|
+
# JSON GET APIs are vulnerable to being embedded as JavaScript while the
|
11
|
+
# Array prototype has been patched to track data. Checks the referrer
|
12
|
+
# even on GET requests if the content type is JSON.
|
13
|
+
class JsonCsrf < Base
|
14
|
+
alias react deny
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
request = Request.new(env)
|
18
|
+
status, headers, body = app.call(env)
|
19
|
+
|
20
|
+
if has_vector? request, headers
|
21
|
+
warn env, "attack prevented by #{self.class}"
|
22
|
+
react(env) or [status, headers, body]
|
23
|
+
else
|
24
|
+
[status, headers, body]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_vector?(request, headers)
|
29
|
+
return false if request.xhr?
|
30
|
+
return false unless headers['Content-Type'].to_s.split(';', 2).first =~ /^\s*application\/json\s*$/
|
31
|
+
origin(request.env).nil? and referrer(request.env) != request.host
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: Directory traversal
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://en.wikipedia.org/wiki/Directory_traversal
|
9
|
+
#
|
10
|
+
# Unescapes '/' and '.', expands +path_info+.
|
11
|
+
# Thus <tt>GET /foo/%2e%2e%2fbar</tt> becomes <tt>GET /bar</tt>.
|
12
|
+
class PathTraversal < Base
|
13
|
+
def call(env)
|
14
|
+
path_was = env["PATH_INFO"]
|
15
|
+
env["PATH_INFO"] = cleanup path_was if path_was && !path_was.empty?
|
16
|
+
app.call env
|
17
|
+
ensure
|
18
|
+
env["PATH_INFO"] = path_was
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleanup(path)
|
22
|
+
if path.respond_to?(:encoding)
|
23
|
+
# Ruby 1.9+ M17N
|
24
|
+
encoding = path.encoding
|
25
|
+
dot = '.'.encode(encoding)
|
26
|
+
slash = '/'.encode(encoding)
|
27
|
+
else
|
28
|
+
# Ruby 1.8
|
29
|
+
dot = '.'
|
30
|
+
slash = '/'
|
31
|
+
end
|
32
|
+
|
33
|
+
parts = []
|
34
|
+
unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash)
|
35
|
+
|
36
|
+
unescaped.split(slash).each do |part|
|
37
|
+
next if part.empty? or part == dot
|
38
|
+
part == '..' ? parts.pop : parts << part
|
39
|
+
end
|
40
|
+
|
41
|
+
cleaned = slash + parts.join(slash)
|
42
|
+
cleaned << slash if parts.any? and unescaped =~ %r{/\.{0,2}$}
|
43
|
+
cleaned
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: CSRF
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
9
|
+
#
|
10
|
+
# Does not accept unsafe HTTP requests if the Referer [sic] header is set to
|
11
|
+
# a different host.
|
12
|
+
class RemoteReferrer < Base
|
13
|
+
default_reaction :deny
|
14
|
+
|
15
|
+
def accepts?(env)
|
16
|
+
safe?(env) or referrer(env) == Request.new(env).host
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: CSRF
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
9
|
+
#
|
10
|
+
# Only accepts unsafe HTTP requests if a given access token matches the token
|
11
|
+
# included in the session *or* the request comes from the same origin.
|
12
|
+
#
|
13
|
+
# Compatible with Rails and rack-csrf.
|
14
|
+
class RemoteToken < AuthenticityToken
|
15
|
+
default_reaction :deny
|
16
|
+
|
17
|
+
def accepts?(env)
|
18
|
+
super or referrer(env) == Request.new(env).host
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: Session Hijacking
|
7
|
+
# Supported browsers:: all
|
8
|
+
# More infos:: http://en.wikipedia.org/wiki/Session_hijacking
|
9
|
+
#
|
10
|
+
# Tracks request properties like the user agent in the session and empties
|
11
|
+
# the session if those properties change. This essentially prevents attacks
|
12
|
+
# from Firesheep. Since all headers taken into consideration can be
|
13
|
+
# spoofed, too, this will not prevent determined hijacking attempts.
|
14
|
+
class SessionHijacking < Base
|
15
|
+
default_reaction :drop_session
|
16
|
+
default_options :tracking_key => :tracking, :encrypt_tracking => true,
|
17
|
+
:track => %w[HTTP_USER_AGENT HTTP_ACCEPT_LANGUAGE]
|
18
|
+
|
19
|
+
def accepts?(env)
|
20
|
+
session = session env
|
21
|
+
key = options[:tracking_key]
|
22
|
+
if session.include? key
|
23
|
+
session[key].all? { |k,v| v == encrypt(env[k]) }
|
24
|
+
else
|
25
|
+
session[key] = {}
|
26
|
+
options[:track].each { |k| session[key][k] = encrypt(env[k]) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def encrypt(value)
|
31
|
+
value = value.to_s.downcase
|
32
|
+
options[:encrypt_tracking] ? super(value) : value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rack
|
2
|
+
module Protection
|
3
|
+
def self.version
|
4
|
+
VERSION
|
5
|
+
end
|
6
|
+
|
7
|
+
SIGNATURE = [1, 5, 3]
|
8
|
+
VERSION = SIGNATURE.join('.')
|
9
|
+
|
10
|
+
VERSION.extend Comparable
|
11
|
+
def VERSION.<=>(other)
|
12
|
+
other = other.split('.').map { |i| i.to_i } if other.respond_to? :split
|
13
|
+
SIGNATURE <=> Array(other)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rack/protection'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Protection
|
5
|
+
##
|
6
|
+
# Prevented attack:: Non-permanent XSS
|
7
|
+
# Supported browsers:: Internet Explorer 8 and later
|
8
|
+
# More infos:: http://blogs.msdn.com/b/ie/archive/2008/07/01/ie8-security-part-iv-the-xss-filter.aspx
|
9
|
+
#
|
10
|
+
# Sets X-XSS-Protection header to tell the browser to block attacks.
|
11
|
+
#
|
12
|
+
# Options:
|
13
|
+
# xss_mode:: How the browser should prevent the attack (default: :block)
|
14
|
+
class XSSHeader < Base
|
15
|
+
default_options :xss_mode => :block, :nosniff => true
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
status, headers, body = @app.call(env)
|
19
|
+
headers['X-XSS-Protection'] ||= "1; mode=#{options[:xss_mode]}" if html? headers
|
20
|
+
headers['X-Content-Type-Options'] ||= 'nosniff' if options[:nosniff]
|
21
|
+
[status, headers, body]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# Run `rake rack-protection.gemspec` to update the gemspec.
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
# general infos
|
4
|
+
s.name = "rack-protection-monkey"
|
5
|
+
s.version = "1.5.3"
|
6
|
+
s.description = "You should use protection! - Monkey Version"
|
7
|
+
s.homepage = "http://github.com/sinatra/rack-protection"
|
8
|
+
s.summary = s.description
|
9
|
+
s.license = 'MIT'
|
10
|
+
|
11
|
+
# generated from git shortlog -sn
|
12
|
+
s.authors = [
|
13
|
+
"Konstantin Haase",
|
14
|
+
"Alex Rodionov",
|
15
|
+
"Patrick Ellis",
|
16
|
+
"Jason Staten",
|
17
|
+
"ITO Nobuaki",
|
18
|
+
"Jeff Welling",
|
19
|
+
"Matteo Centenaro",
|
20
|
+
"Egor Homakov",
|
21
|
+
"Florian Gilcher",
|
22
|
+
"Fojas",
|
23
|
+
"Igor Bochkariov",
|
24
|
+
"Mael Clerambault",
|
25
|
+
"Martin Mauch",
|
26
|
+
"Renne Nissinen",
|
27
|
+
"SAKAI, Kazuaki",
|
28
|
+
"Stanislav Savulchik",
|
29
|
+
"Steve Agalloco",
|
30
|
+
"TOBY",
|
31
|
+
"Thais Camilo and Konstantin Haase",
|
32
|
+
"Vipul A M",
|
33
|
+
"Akzhan Abdulin",
|
34
|
+
"brookemckim",
|
35
|
+
"Bj\u{f8}rge N\u{e6}ss",
|
36
|
+
"Chris Heald",
|
37
|
+
"Chris Mytton",
|
38
|
+
"Corey Ward",
|
39
|
+
"Dario Cravero",
|
40
|
+
"David Kellum"
|
41
|
+
]
|
42
|
+
|
43
|
+
# generated from git shortlog -sne
|
44
|
+
s.email = [
|
45
|
+
"konstantin.mailinglists@googlemail.com",
|
46
|
+
"p0deje@gmail.com",
|
47
|
+
"jstaten07@gmail.com",
|
48
|
+
"patrick@soundcloud.com",
|
49
|
+
"jeff.welling@gmail.com",
|
50
|
+
"bugant@gmail.com",
|
51
|
+
"daydream.trippers@gmail.com",
|
52
|
+
"florian.gilcher@asquera.de",
|
53
|
+
"developer@fojasaur.us",
|
54
|
+
"ujifgc@gmail.com",
|
55
|
+
"mael@clerambault.fr",
|
56
|
+
"martin.mauch@gmail.com",
|
57
|
+
"rennex@iki.fi",
|
58
|
+
"kaz.july.7@gmail.com",
|
59
|
+
"s.savulchik@gmail.com",
|
60
|
+
"steve.agalloco@gmail.com",
|
61
|
+
"toby.net.info.mail+git@gmail.com",
|
62
|
+
"dev+narwen+rkh@rkh.im",
|
63
|
+
"vipulnsward@gmail.com",
|
64
|
+
"akzhan.abdulin@gmail.com",
|
65
|
+
"brooke@digitalocean.com",
|
66
|
+
"bjoerge@bengler.no",
|
67
|
+
"cheald@gmail.com",
|
68
|
+
"self@hecticjeff.net",
|
69
|
+
"coreyward@me.com",
|
70
|
+
"dario@uxtemple.com",
|
71
|
+
"dek-oss@gravitext.com",
|
72
|
+
"homakov@gmail.com"
|
73
|
+
]
|
74
|
+
|
75
|
+
# generated from git ls-files
|
76
|
+
s.files = [
|
77
|
+
"License",
|
78
|
+
"README.md",
|
79
|
+
"Rakefile",
|
80
|
+
"lib/rack-protection.rb",
|
81
|
+
"lib/rack/protection.rb",
|
82
|
+
"lib/rack/protection/authenticity_token.rb",
|
83
|
+
"lib/rack/protection/base.rb",
|
84
|
+
"lib/rack/protection/escaped_params.rb",
|
85
|
+
"lib/rack/protection/form_token.rb",
|
86
|
+
"lib/rack/protection/frame_options.rb",
|
87
|
+
"lib/rack/protection/http_origin.rb",
|
88
|
+
"lib/rack/protection/ip_spoofing.rb",
|
89
|
+
"lib/rack/protection/json_csrf.rb",
|
90
|
+
"lib/rack/protection/path_traversal.rb",
|
91
|
+
"lib/rack/protection/remote_referrer.rb",
|
92
|
+
"lib/rack/protection/remote_token.rb",
|
93
|
+
"lib/rack/protection/session_hijacking.rb",
|
94
|
+
"lib/rack/protection/version.rb",
|
95
|
+
"lib/rack/protection/xss_header.rb",
|
96
|
+
"rack-protection.gemspec",
|
97
|
+
"spec/lib/rack/protection/authenticity_token_spec.rb",
|
98
|
+
"spec/lib/rack/protection/base_spec.rb",
|
99
|
+
"spec/lib/rack/protection/escaped_params_spec.rb",
|
100
|
+
"spec/lib/rack/protection/form_token_spec.rb",
|
101
|
+
"spec/lib/rack/protection/frame_options_spec.rb",
|
102
|
+
"spec/lib/rack/protection/http_origin_spec.rb",
|
103
|
+
"spec/lib/rack/protection/ip_spoofing_spec.rb",
|
104
|
+
"spec/lib/rack/protection/json_csrf_spec.rb",
|
105
|
+
"spec/lib/rack/protection/path_traversal_spec.rb",
|
106
|
+
"spec/lib/rack/protection/protection_spec.rb",
|
107
|
+
"spec/lib/rack/protection/remote_referrer_spec.rb",
|
108
|
+
"spec/lib/rack/protection/remote_token_spec.rb",
|
109
|
+
"spec/lib/rack/protection/session_hijacking_spec.rb",
|
110
|
+
"spec/lib/rack/protection/xss_header_spec.rb",
|
111
|
+
"spec/spec_helper.rb",
|
112
|
+
"spec/support/dummy_app.rb",
|
113
|
+
"spec/support/not_implemented_as_pending.rb",
|
114
|
+
"spec/support/rack_monkey_patches.rb",
|
115
|
+
"spec/support/shared_examples.rb",
|
116
|
+
"spec/support/spec_helpers.rb"
|
117
|
+
]
|
118
|
+
|
119
|
+
# dependencies
|
120
|
+
s.add_dependency "rack"
|
121
|
+
s.add_development_dependency "rack-test"
|
122
|
+
s.add_development_dependency "rspec", "~> 3.0.0"
|
123
|
+
end
|