rack-protection 2.0.8.1

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.
@@ -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,57 @@
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/0.10/security/#json-security
9
+ # http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
10
+ #
11
+ # JSON GET APIs are vulnerable to being embedded as JavaScript when the
12
+ # Array prototype has been patched to track data. Checks the referrer
13
+ # even on GET requests if the content type is JSON.
14
+ #
15
+ # If request includes Origin HTTP header, defers to HttpOrigin to determine
16
+ # if the request is safe. Please refer to the documentation for more info.
17
+ #
18
+ # The `:allow_if` option can be set to a proc to use custom allow/deny logic.
19
+ class JsonCsrf < Base
20
+ default_options :allow_if => nil
21
+
22
+ alias react deny
23
+
24
+ def call(env)
25
+ request = Request.new(env)
26
+ status, headers, body = app.call(env)
27
+
28
+ if has_vector?(request, headers)
29
+ warn env, "attack prevented by #{self.class}"
30
+
31
+ react_and_close(env, body) or [status, headers, body]
32
+ else
33
+ [status, headers, body]
34
+ end
35
+ end
36
+
37
+ def has_vector?(request, headers)
38
+ return false if request.xhr?
39
+ return false if options[:allow_if] && options[:allow_if].call(request.env)
40
+ return false unless headers['Content-Type'].to_s.split(';', 2).first =~ /^\s*application\/json\s*$/
41
+ origin(request.env).nil? and referrer(request.env) != request.host
42
+ end
43
+
44
+ def react_and_close(env, body)
45
+ reaction = react(env)
46
+
47
+ close_body(body) if reaction
48
+
49
+ reaction
50
+ end
51
+
52
+ def close_body(body)
53
+ body.close if body.respond_to?(:close)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,42 @@
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
+ encoding = path.encoding
23
+ dot = '.'.encode(encoding)
24
+ slash = '/'.encode(encoding)
25
+ backslash = '\\'.encode(encoding)
26
+
27
+ parts = []
28
+ unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash).gsub(/%5c/i, backslash)
29
+ unescaped = unescaped.gsub(backslash, slash)
30
+
31
+ unescaped.split(slash).each do |part|
32
+ next if part.empty? or part == dot
33
+ part == '..' ? parts.pop : parts << part
34
+ end
35
+
36
+ cleaned = slash + parts.join(slash)
37
+ cleaned << slash if parts.any? and unescaped =~ %r{/\.{0,2}$}
38
+ cleaned
39
+ end
40
+ end
41
+ end
42
+ 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 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]
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,39 @@
1
+ require 'rack/protection'
2
+
3
+ module Rack
4
+ module Protection
5
+ ##
6
+ # Prevented attack:: Protects against against protocol downgrade attacks and cookie hijacking.
7
+ # Supported browsers:: all
8
+ # More infos:: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
9
+ #
10
+ # browser will prevent any communications from being sent over HTTP
11
+ # to the specified domain and will instead send all communications over HTTPS.
12
+ # It also prevents HTTPS click through prompts on browsers.
13
+ #
14
+ # Options:
15
+ #
16
+ # max_age:: How long future requests to the domain should go over HTTPS; specified in seconds
17
+ # include_subdomains:: If all present and future subdomains will be HTTPS
18
+ # preload:: Allow this domain to be included in browsers HSTS preload list. See https://hstspreload.appspot.com/
19
+
20
+ class StrictTransport < Base
21
+ default_options :max_age => 31_536_000, :include_subdomains => false, :preload => false
22
+
23
+ def strict_transport
24
+ @strict_transport ||= begin
25
+ strict_transport = 'max-age=' + options[:max_age].to_s
26
+ strict_transport += '; includeSubDomains' if options[:include_subdomains]
27
+ strict_transport += '; preload' if options[:preload]
28
+ strict_transport.to_str
29
+ end
30
+ end
31
+
32
+ def call(env)
33
+ status, headers, body = @app.call(env)
34
+ headers['Strict-Transport-Security'] ||= strict_transport
35
+ [status, headers, body]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ module Protection
3
+ VERSION = '2.0.8.1'
4
+ end
5
+ 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 Chrome
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,40 @@
1
+ version = File.read(File.expand_path("../../VERSION", __FILE__)).strip
2
+
3
+ Gem::Specification.new do |s|
4
+ # general infos
5
+ s.name = "rack-protection"
6
+ s.version = version
7
+ s.description = "Protect against typical web attacks, works with all Rack apps, including Rails."
8
+ s.homepage = "http://sinatrarb.com/protection/"
9
+ s.summary = s.description
10
+ s.license = 'MIT'
11
+ s.authors = ["https://github.com/sinatra/sinatra/graphs/contributors"]
12
+ s.email = "sinatrarb@googlegroups.com"
13
+ s.files = Dir["lib/**/*.rb"] + [
14
+ "License",
15
+ "README.md",
16
+ "Rakefile",
17
+ "Gemfile",
18
+ "rack-protection.gemspec"
19
+ ]
20
+
21
+ if s.respond_to?(:metadata)
22
+ s.metadata = {
23
+ 'source_code_uri' => 'https://github.com/sinatra/sinatra/tree/master/rack-protection',
24
+ 'homepage_uri' => 'http://sinatrarb.com/protection/',
25
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/rack-protection'
26
+ }
27
+ else
28
+ raise <<-EOF
29
+ RubyGems 2.0 or newer is required to protect against public gem pushes. You can update your rubygems version by running:
30
+ gem install rubygems-update
31
+ update_rubygems:
32
+ gem update --system
33
+ EOF
34
+ end
35
+
36
+ # dependencies
37
+ s.add_dependency "rack"
38
+ s.add_development_dependency "rack-test"
39
+ s.add_development_dependency "rspec", "~> 3.6"
40
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-protection
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.8.1
5
+ platform: ruby
6
+ authors:
7
+ - https://github.com/sinatra/sinatra/graphs/contributors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack-test
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.6'
55
+ description: Protect against typical web attacks, works with all Rack apps, including
56
+ Rails.
57
+ email: sinatrarb@googlegroups.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Gemfile
63
+ - License
64
+ - README.md
65
+ - Rakefile
66
+ - lib/rack-protection.rb
67
+ - lib/rack/protection.rb
68
+ - lib/rack/protection/authenticity_token.rb
69
+ - lib/rack/protection/base.rb
70
+ - lib/rack/protection/content_security_policy.rb
71
+ - lib/rack/protection/cookie_tossing.rb
72
+ - lib/rack/protection/escaped_params.rb
73
+ - lib/rack/protection/form_token.rb
74
+ - lib/rack/protection/frame_options.rb
75
+ - lib/rack/protection/http_origin.rb
76
+ - lib/rack/protection/ip_spoofing.rb
77
+ - lib/rack/protection/json_csrf.rb
78
+ - lib/rack/protection/path_traversal.rb
79
+ - lib/rack/protection/remote_referrer.rb
80
+ - lib/rack/protection/remote_token.rb
81
+ - lib/rack/protection/session_hijacking.rb
82
+ - lib/rack/protection/strict_transport.rb
83
+ - lib/rack/protection/version.rb
84
+ - lib/rack/protection/xss_header.rb
85
+ - rack-protection.gemspec
86
+ homepage: http://sinatrarb.com/protection/
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ source_code_uri: https://github.com/sinatra/sinatra/tree/master/rack-protection
91
+ homepage_uri: http://sinatrarb.com/protection/
92
+ documentation_uri: https://www.rubydoc.info/gems/rack-protection
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.7.3
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Protect against typical web attacks, works with all Rack apps, including
113
+ Rails.
114
+ test_files: []