homura-runtime 0.3.3 → 0.3.4
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/CHANGELOG.md +7 -0
- data/lib/homura/runtime/version.rb +1 -1
- data/vendor/rack/auth/abstract/handler.rb +41 -0
- data/vendor/rack/auth/abstract/request.rb +51 -0
- data/vendor/rack/auth/basic.rb +58 -0
- data/vendor/rack/bad_request.rb +8 -0
- data/vendor/rack/body_proxy.rb +63 -0
- data/vendor/rack/builder.rb +315 -0
- data/vendor/rack/cascade.rb +67 -0
- data/vendor/rack/common_logger.rb +94 -0
- data/vendor/rack/conditional_get.rb +87 -0
- data/vendor/rack/config.rb +22 -0
- data/vendor/rack/constants.rb +68 -0
- data/vendor/rack/content_length.rb +34 -0
- data/vendor/rack/content_type.rb +33 -0
- data/vendor/rack/deflater.rb +159 -0
- data/vendor/rack/directory.rb +210 -0
- data/vendor/rack/etag.rb +71 -0
- data/vendor/rack/events.rb +172 -0
- data/vendor/rack/files.rb +224 -0
- data/vendor/rack/head.rb +25 -0
- data/vendor/rack/headers.rb +238 -0
- data/vendor/rack/lint.rb +1000 -0
- data/vendor/rack/lock.rb +29 -0
- data/vendor/rack/media_type.rb +42 -0
- data/vendor/rack/method_override.rb +56 -0
- data/vendor/rack/mime.rb +694 -0
- data/vendor/rack/mock.rb +3 -0
- data/vendor/rack/mock_request.rb +161 -0
- data/vendor/rack/mock_response.rb +147 -0
- data/vendor/rack/multipart/generator.rb +99 -0
- data/vendor/rack/multipart/parser.rb +586 -0
- data/vendor/rack/multipart/uploaded_file.rb +82 -0
- data/vendor/rack/multipart.rb +77 -0
- data/vendor/rack/null_logger.rb +48 -0
- data/vendor/rack/protection/authenticity_token.rb +256 -0
- data/vendor/rack/protection/base.rb +140 -0
- data/vendor/rack/protection/content_security_policy.rb +80 -0
- data/vendor/rack/protection/cookie_tossing.rb +77 -0
- data/vendor/rack/protection/escaped_params.rb +93 -0
- data/vendor/rack/protection/form_token.rb +25 -0
- data/vendor/rack/protection/frame_options.rb +39 -0
- data/vendor/rack/protection/http_origin.rb +43 -0
- data/vendor/rack/protection/ip_spoofing.rb +27 -0
- data/vendor/rack/protection/json_csrf.rb +60 -0
- data/vendor/rack/protection/path_traversal.rb +45 -0
- data/vendor/rack/protection/referrer_policy.rb +27 -0
- data/vendor/rack/protection/remote_referrer.rb +22 -0
- data/vendor/rack/protection/remote_token.rb +24 -0
- data/vendor/rack/protection/session_hijacking.rb +37 -0
- data/vendor/rack/protection/strict_transport.rb +41 -0
- data/vendor/rack/protection/version.rb +7 -0
- data/vendor/rack/protection/xss_header.rb +27 -0
- data/vendor/rack/protection.rb +58 -0
- data/vendor/rack/query_parser.rb +261 -0
- data/vendor/rack/recursive.rb +66 -0
- data/vendor/rack/reloader.rb +112 -0
- data/vendor/rack/request.rb +818 -0
- data/vendor/rack/response.rb +403 -0
- data/vendor/rack/rewindable_input.rb +116 -0
- data/vendor/rack/runtime.rb +35 -0
- data/vendor/rack/sendfile.rb +197 -0
- data/vendor/rack/session/abstract/id.rb +533 -0
- data/vendor/rack/session/constants.rb +13 -0
- data/vendor/rack/session/cookie.rb +292 -0
- data/vendor/rack/session/encryptor.rb +415 -0
- data/vendor/rack/session/pool.rb +76 -0
- data/vendor/rack/session/version.rb +10 -0
- data/vendor/rack/session.rb +12 -0
- data/vendor/rack/show_exceptions.rb +433 -0
- data/vendor/rack/show_status.rb +121 -0
- data/vendor/rack/static.rb +188 -0
- data/vendor/rack/tempfile_reaper.rb +44 -0
- data/vendor/rack/urlmap.rb +99 -0
- data/vendor/rack/utils.rb +631 -0
- data/vendor/rack/version.rb +17 -0
- data/vendor/rack.rb +66 -0
- metadata +76 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
require 'rack/utils'
|
|
5
|
+
# require 'tempfile'
|
|
6
|
+
|
|
7
|
+
# begin
|
|
8
|
+
# require 'escape_utils'
|
|
9
|
+
# rescue LoadError
|
|
10
|
+
# end
|
|
11
|
+
|
|
12
|
+
module Rack
|
|
13
|
+
module Protection
|
|
14
|
+
##
|
|
15
|
+
# Prevented attack:: XSS
|
|
16
|
+
# Supported browsers:: all
|
|
17
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_scripting
|
|
18
|
+
#
|
|
19
|
+
# Automatically escapes Rack::Request#params so they can be embedded in HTML
|
|
20
|
+
# or JavaScript without any further issues.
|
|
21
|
+
#
|
|
22
|
+
# Options:
|
|
23
|
+
# escape:: What escaping modes to use, should be Symbol or Array of Symbols.
|
|
24
|
+
# Available: :html (default), :javascript, :url
|
|
25
|
+
class EscapedParams < Base
|
|
26
|
+
extend Rack::Utils
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
alias escape_url escape
|
|
30
|
+
public :escape_html
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
default_options escape: :html,
|
|
34
|
+
escaper: defined?(EscapeUtils) ? EscapeUtils : self
|
|
35
|
+
|
|
36
|
+
def initialize(*)
|
|
37
|
+
super
|
|
38
|
+
|
|
39
|
+
modes = Array options[:escape]
|
|
40
|
+
@escaper = options[:escaper]
|
|
41
|
+
@html = modes.include? :html
|
|
42
|
+
@javascript = modes.include? :javascript
|
|
43
|
+
@url = modes.include? :url
|
|
44
|
+
|
|
45
|
+
return unless @javascript && (!@escaper.respond_to? :escape_javascript)
|
|
46
|
+
|
|
47
|
+
raise('Use EscapeUtils for JavaScript escaping.')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def call(env)
|
|
51
|
+
request = Request.new(env)
|
|
52
|
+
get_was = handle(request.GET)
|
|
53
|
+
post_was = begin
|
|
54
|
+
handle(request.POST)
|
|
55
|
+
rescue StandardError
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
app.call env
|
|
59
|
+
ensure
|
|
60
|
+
request.GET.replace get_was if get_was
|
|
61
|
+
request.POST.replace post_was if post_was
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def handle(hash)
|
|
65
|
+
was = hash.dup
|
|
66
|
+
hash.replace escape(hash)
|
|
67
|
+
was
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def escape(object)
|
|
71
|
+
case object
|
|
72
|
+
when Hash then escape_hash(object)
|
|
73
|
+
when Array then object.map { |o| escape(o) }
|
|
74
|
+
when String then escape_string(object)
|
|
75
|
+
when Tempfile then object
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def escape_hash(hash)
|
|
80
|
+
hash = hash.dup
|
|
81
|
+
hash.each { |k, v| hash[k] = escape(v) }
|
|
82
|
+
hash
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def escape_string(str)
|
|
86
|
+
str = @escaper.escape_url(str) if @url
|
|
87
|
+
str = @escaper.escape_html(str) if @html
|
|
88
|
+
str = @escaper.escape_javascript(str) if @javascript
|
|
89
|
+
str
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: CSRF
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
|
11
|
+
#
|
|
12
|
+
# Only accepts submitted forms if a given access token matches the token
|
|
13
|
+
# included in the session. Does not expect such a token from Ajax request.
|
|
14
|
+
#
|
|
15
|
+
# This middleware is not used when using the Rack::Protection collection,
|
|
16
|
+
# since it might be a security issue, depending on your application
|
|
17
|
+
#
|
|
18
|
+
# Compatible with rack-csrf.
|
|
19
|
+
class FormToken < AuthenticityToken
|
|
20
|
+
def accepts?(env)
|
|
21
|
+
env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' or super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: Clickjacking
|
|
9
|
+
# Supported browsers:: Internet Explorer 8, Firefox 3.6.9, Opera 10.50,
|
|
10
|
+
# Safari 4.0, Chrome 4.1.249.1042 and later
|
|
11
|
+
# More infos:: https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header
|
|
12
|
+
#
|
|
13
|
+
# Sets X-Frame-Options header to tell the browser avoid embedding the page
|
|
14
|
+
# in a frame.
|
|
15
|
+
#
|
|
16
|
+
# Options:
|
|
17
|
+
#
|
|
18
|
+
# frame_options:: Defines who should be allowed to embed the page in a
|
|
19
|
+
# frame. Use :deny to forbid any embedding, :sameorigin
|
|
20
|
+
# to allow embedding from the same origin (default).
|
|
21
|
+
class FrameOptions < Base
|
|
22
|
+
default_options frame_options: :sameorigin
|
|
23
|
+
|
|
24
|
+
def frame_options
|
|
25
|
+
@frame_options ||= begin
|
|
26
|
+
frame_options = options[:frame_options]
|
|
27
|
+
frame_options = options[:frame_options].to_s.upcase unless frame_options.respond_to? :to_str
|
|
28
|
+
frame_options.to_str
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def call(env)
|
|
33
|
+
status, headers, body = @app.call(env)
|
|
34
|
+
headers['x-frame-options'] ||= frame_options if html? headers
|
|
35
|
+
[status, headers, body]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: CSRF
|
|
9
|
+
# Supported browsers:: Google Chrome 2, Safari 4 and later
|
|
10
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
|
11
|
+
# http://tools.ietf.org/html/draft-abarth-origin
|
|
12
|
+
#
|
|
13
|
+
# Does not accept unsafe HTTP requests when value of Origin HTTP request header
|
|
14
|
+
# does not match default or permitted URIs.
|
|
15
|
+
#
|
|
16
|
+
# If you want to permit a specific domain, you can pass in as the `:permitted_origins` option:
|
|
17
|
+
#
|
|
18
|
+
# use Rack::Protection, permitted_origins: ["http://localhost:3000", "http://127.0.01:3000"]
|
|
19
|
+
#
|
|
20
|
+
# The `:allow_if` option can also be set to a proc to use custom allow/deny logic.
|
|
21
|
+
class HttpOrigin < Base
|
|
22
|
+
DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 }
|
|
23
|
+
default_reaction :deny
|
|
24
|
+
default_options allow_if: nil
|
|
25
|
+
|
|
26
|
+
def base_url(env)
|
|
27
|
+
request = Rack::Request.new(env)
|
|
28
|
+
port = ":#{request.port}" unless request.port == DEFAULT_PORTS[request.scheme]
|
|
29
|
+
"#{request.scheme}://#{request.host}#{port}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def accepts?(env)
|
|
33
|
+
return true if safe? env
|
|
34
|
+
return true unless (origin = env['HTTP_ORIGIN'])
|
|
35
|
+
return true if base_url(env) == origin
|
|
36
|
+
return true if options[:allow_if]&.call(env)
|
|
37
|
+
|
|
38
|
+
permitted_origins = options[:permitted_origins]
|
|
39
|
+
Array(permitted_origins).include? origin
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: IP spoofing
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://blog.c22.cc/2011/04/22/surveymonkey-ip-spoofing/
|
|
11
|
+
#
|
|
12
|
+
# Detect (some) IP spoofing attacks.
|
|
13
|
+
class IPSpoofing < Base
|
|
14
|
+
default_reaction :deny
|
|
15
|
+
|
|
16
|
+
def accepts?(env)
|
|
17
|
+
return true unless env.include? 'HTTP_X_FORWARDED_FOR'
|
|
18
|
+
|
|
19
|
+
ips = env['HTTP_X_FORWARDED_FOR'].split(',').map(&:strip)
|
|
20
|
+
return false if env.include?('HTTP_CLIENT_IP') && (!ips.include? env['HTTP_CLIENT_IP'])
|
|
21
|
+
return false if env.include?('HTTP_X_REAL_IP') && (!ips.include? env['HTTP_X_REAL_IP'])
|
|
22
|
+
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: CSRF
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://flask.pocoo.org/docs/0.10/security/#json-security
|
|
11
|
+
# http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
|
12
|
+
#
|
|
13
|
+
# JSON GET APIs are vulnerable to being embedded as JavaScript when the
|
|
14
|
+
# Array prototype has been patched to track data. Checks the referrer
|
|
15
|
+
# even on GET requests if the content type is JSON.
|
|
16
|
+
#
|
|
17
|
+
# If request includes Origin HTTP header, defers to HttpOrigin to determine
|
|
18
|
+
# if the request is safe. Please refer to the documentation for more info.
|
|
19
|
+
#
|
|
20
|
+
# The `:allow_if` option can be set to a proc to use custom allow/deny logic.
|
|
21
|
+
class JsonCsrf < Base
|
|
22
|
+
default_options allow_if: nil
|
|
23
|
+
|
|
24
|
+
alias react deny
|
|
25
|
+
|
|
26
|
+
def call(env)
|
|
27
|
+
request = Request.new(env)
|
|
28
|
+
status, headers, body = app.call(env)
|
|
29
|
+
|
|
30
|
+
if has_vector?(request, headers)
|
|
31
|
+
warn env, "attack prevented by #{self.class}"
|
|
32
|
+
|
|
33
|
+
react_and_close(env, body) or [status, headers, body]
|
|
34
|
+
else
|
|
35
|
+
[status, headers, body]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def has_vector?(request, headers)
|
|
40
|
+
return false if request.xhr?
|
|
41
|
+
return false if options[:allow_if]&.call(request.env)
|
|
42
|
+
return false unless headers['content-type'].to_s.split(';', 2).first =~ %r{^\s*application/json\s*$}
|
|
43
|
+
|
|
44
|
+
origin(request.env).nil? and referrer(request.env) != request.host
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def react_and_close(env, body)
|
|
48
|
+
reaction = react(env)
|
|
49
|
+
|
|
50
|
+
close_body(body) if reaction
|
|
51
|
+
|
|
52
|
+
reaction
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def close_body(body)
|
|
56
|
+
body.close if body.respond_to?(:close)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: Directory traversal
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://en.wikipedia.org/wiki/Directory_traversal
|
|
11
|
+
#
|
|
12
|
+
# Unescapes '/' and '.', expands +path_info+.
|
|
13
|
+
# Thus <tt>GET /foo/%2e%2e%2fbar</tt> becomes <tt>GET /bar</tt>.
|
|
14
|
+
class PathTraversal < Base
|
|
15
|
+
def call(env)
|
|
16
|
+
path_was = env['PATH_INFO']
|
|
17
|
+
env['PATH_INFO'] = cleanup path_was if path_was && !path_was.empty?
|
|
18
|
+
app.call env
|
|
19
|
+
ensure
|
|
20
|
+
env['PATH_INFO'] = path_was
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cleanup(path)
|
|
24
|
+
encoding = path.encoding
|
|
25
|
+
dot = '.'.encode(encoding)
|
|
26
|
+
slash = '/'.encode(encoding)
|
|
27
|
+
backslash = '\\'.encode(encoding)
|
|
28
|
+
|
|
29
|
+
parts = []
|
|
30
|
+
unescaped = path.gsub(/%2e/i, dot).gsub(/%2f/i, slash).gsub(/%5c/i, backslash)
|
|
31
|
+
unescaped = unescaped.gsub(backslash, slash)
|
|
32
|
+
|
|
33
|
+
unescaped.split(slash).each do |part|
|
|
34
|
+
next if part.empty? || (part == dot)
|
|
35
|
+
|
|
36
|
+
part == '..' ? parts.pop : parts << part
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
cleaned = slash + parts.join(slash)
|
|
40
|
+
cleaned << slash if parts.any? && unescaped =~ (%r{/\.{0,2}$})
|
|
41
|
+
cleaned
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: Secret leakage, third party tracking
|
|
9
|
+
# Supported browsers:: mixed support
|
|
10
|
+
# More infos:: https://www.w3.org/TR/referrer-policy/
|
|
11
|
+
# https://caniuse.com/#search=referrer-policy
|
|
12
|
+
#
|
|
13
|
+
# Sets Referrer-Policy header to tell the browser to limit the Referer header.
|
|
14
|
+
#
|
|
15
|
+
# Options:
|
|
16
|
+
# referrer_policy:: The policy to use (default: 'strict-origin-when-cross-origin')
|
|
17
|
+
class ReferrerPolicy < Base
|
|
18
|
+
default_options referrer_policy: 'strict-origin-when-cross-origin'
|
|
19
|
+
|
|
20
|
+
def call(env)
|
|
21
|
+
status, headers, body = @app.call(env)
|
|
22
|
+
headers['referrer-policy'] ||= options[:referrer_policy]
|
|
23
|
+
[status, headers, body]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: CSRF
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
|
11
|
+
#
|
|
12
|
+
# Does not accept unsafe HTTP requests if the Referer [sic] header is set to
|
|
13
|
+
# a different host.
|
|
14
|
+
class RemoteReferrer < Base
|
|
15
|
+
default_reaction :deny
|
|
16
|
+
|
|
17
|
+
def accepts?(env)
|
|
18
|
+
safe?(env) or referrer(env) == Request.new(env).host
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: CSRF
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://en.wikipedia.org/wiki/Cross-site_request_forgery
|
|
11
|
+
#
|
|
12
|
+
# Only accepts unsafe HTTP requests if a given access token matches the token
|
|
13
|
+
# included in the session *or* the request comes from the same origin.
|
|
14
|
+
#
|
|
15
|
+
# Compatible with rack-csrf.
|
|
16
|
+
class RemoteToken < AuthenticityToken
|
|
17
|
+
default_reaction :deny
|
|
18
|
+
|
|
19
|
+
def accepts?(env)
|
|
20
|
+
super or referrer(env) == Request.new(env).host
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: Session Hijacking
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: http://en.wikipedia.org/wiki/Session_hijacking
|
|
11
|
+
#
|
|
12
|
+
# Tracks request properties like the user agent in the session and empties
|
|
13
|
+
# the session if those properties change. This essentially prevents attacks
|
|
14
|
+
# from Firesheep. Since all headers taken into consideration can be
|
|
15
|
+
# spoofed, too, this will not prevent determined hijacking attempts.
|
|
16
|
+
class SessionHijacking < Base
|
|
17
|
+
default_reaction :drop_session
|
|
18
|
+
default_options tracking_key: :tracking,
|
|
19
|
+
track: %w[HTTP_USER_AGENT]
|
|
20
|
+
|
|
21
|
+
def accepts?(env)
|
|
22
|
+
session = session env
|
|
23
|
+
key = options[:tracking_key]
|
|
24
|
+
if session.include? key
|
|
25
|
+
session[key].all? { |k, v| v == encode(env[k]) }
|
|
26
|
+
else
|
|
27
|
+
session[key] = {}
|
|
28
|
+
options[:track].each { |k| session[key][k] = encode(env[k]) }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def encode(value)
|
|
33
|
+
value.to_s.downcase
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: Protects against against protocol downgrade attacks and cookie hijacking.
|
|
9
|
+
# Supported browsers:: all
|
|
10
|
+
# More infos:: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
|
|
11
|
+
#
|
|
12
|
+
# browser will prevent any communications from being sent over HTTP
|
|
13
|
+
# to the specified domain and will instead send all communications over HTTPS.
|
|
14
|
+
# It also prevents HTTPS click through prompts on browsers.
|
|
15
|
+
#
|
|
16
|
+
# Options:
|
|
17
|
+
#
|
|
18
|
+
# max_age:: How long future requests to the domain should go over HTTPS; specified in seconds
|
|
19
|
+
# include_subdomains:: If all present and future subdomains will be HTTPS
|
|
20
|
+
# preload:: Allow this domain to be included in browsers HSTS preload list. See https://hstspreload.appspot.com/
|
|
21
|
+
|
|
22
|
+
class StrictTransport < Base
|
|
23
|
+
default_options max_age: 31_536_000, include_subdomains: false, preload: false
|
|
24
|
+
|
|
25
|
+
def strict_transport
|
|
26
|
+
@strict_transport ||= begin
|
|
27
|
+
strict_transport = "max-age=#{options[:max_age]}"
|
|
28
|
+
strict_transport += '; includeSubDomains' if options[:include_subdomains]
|
|
29
|
+
strict_transport += '; preload' if options[:preload]
|
|
30
|
+
strict_transport.to_str
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def call(env)
|
|
35
|
+
status, headers, body = @app.call(env)
|
|
36
|
+
headers['strict-transport-security'] ||= strict_transport
|
|
37
|
+
[status, headers, body]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection'
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
module Protection
|
|
7
|
+
##
|
|
8
|
+
# Prevented attack:: Non-permanent XSS
|
|
9
|
+
# Supported browsers:: Internet Explorer 8+ and Chrome
|
|
10
|
+
# More infos:: http://blogs.msdn.com/b/ie/archive/2008/07/01/ie8-security-part-iv-the-xss-filter.aspx
|
|
11
|
+
#
|
|
12
|
+
# Sets X-XSS-Protection header to tell the browser to block attacks.
|
|
13
|
+
#
|
|
14
|
+
# Options:
|
|
15
|
+
# xss_mode:: How the browser should prevent the attack (default: :block)
|
|
16
|
+
class XSSHeader < Base
|
|
17
|
+
default_options xss_mode: :block, nosniff: true
|
|
18
|
+
|
|
19
|
+
def call(env)
|
|
20
|
+
status, headers, body = @app.call(env)
|
|
21
|
+
headers['x-xss-protection'] ||= "1; mode=#{options[:xss_mode]}" if html? headers
|
|
22
|
+
headers['x-content-type-options'] ||= 'nosniff' if options[:nosniff]
|
|
23
|
+
[status, headers, body]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/protection/version'
|
|
4
|
+
require 'rack'
|
|
5
|
+
|
|
6
|
+
module Rack
|
|
7
|
+
module Protection
|
|
8
|
+
autoload :AuthenticityToken, 'rack/protection/authenticity_token'
|
|
9
|
+
autoload :Base, 'rack/protection/base'
|
|
10
|
+
autoload :CookieTossing, 'rack/protection/cookie_tossing'
|
|
11
|
+
autoload :ContentSecurityPolicy, 'rack/protection/content_security_policy'
|
|
12
|
+
autoload :EscapedParams, 'rack/protection/escaped_params'
|
|
13
|
+
autoload :FormToken, 'rack/protection/form_token'
|
|
14
|
+
autoload :FrameOptions, 'rack/protection/frame_options'
|
|
15
|
+
autoload :HttpOrigin, 'rack/protection/http_origin'
|
|
16
|
+
autoload :IPSpoofing, 'rack/protection/ip_spoofing'
|
|
17
|
+
autoload :JsonCsrf, 'rack/protection/json_csrf'
|
|
18
|
+
autoload :PathTraversal, 'rack/protection/path_traversal'
|
|
19
|
+
autoload :ReferrerPolicy, 'rack/protection/referrer_policy'
|
|
20
|
+
autoload :RemoteReferrer, 'rack/protection/remote_referrer'
|
|
21
|
+
autoload :RemoteToken, 'rack/protection/remote_token'
|
|
22
|
+
autoload :SessionHijacking, 'rack/protection/session_hijacking'
|
|
23
|
+
autoload :StrictTransport, 'rack/protection/strict_transport'
|
|
24
|
+
autoload :XSSHeader, 'rack/protection/xss_header'
|
|
25
|
+
|
|
26
|
+
def self.new(app, options = {})
|
|
27
|
+
except = Array options[:except]
|
|
28
|
+
use_these = Array options[:use]
|
|
29
|
+
|
|
30
|
+
if options.fetch(:without_session, false)
|
|
31
|
+
except += %i[remote_token]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Rack::Builder.new do
|
|
35
|
+
# Off by default, unless added
|
|
36
|
+
use ::Rack::Protection::AuthenticityToken, options if use_these.include? :authenticity_token
|
|
37
|
+
use ::Rack::Protection::ContentSecurityPolicy, options if use_these.include? :content_security_policy
|
|
38
|
+
use ::Rack::Protection::CookieTossing, options if use_these.include? :cookie_tossing
|
|
39
|
+
use ::Rack::Protection::EscapedParams, options if use_these.include? :escaped_params
|
|
40
|
+
use ::Rack::Protection::FormToken, options if use_these.include? :form_token
|
|
41
|
+
use ::Rack::Protection::ReferrerPolicy, options if use_these.include? :referrer_policy
|
|
42
|
+
use ::Rack::Protection::RemoteReferrer, options if use_these.include? :remote_referrer
|
|
43
|
+
use ::Rack::Protection::SessionHijacking, options if use_these.include? :session_hijacking
|
|
44
|
+
use ::Rack::Protection::StrictTransport, options if use_these.include? :strict_transport
|
|
45
|
+
|
|
46
|
+
# On by default, unless skipped
|
|
47
|
+
use ::Rack::Protection::FrameOptions, options unless except.include? :frame_options
|
|
48
|
+
use ::Rack::Protection::HttpOrigin, options unless except.include? :http_origin
|
|
49
|
+
use ::Rack::Protection::IPSpoofing, options unless except.include? :ip_spoofing
|
|
50
|
+
use ::Rack::Protection::JsonCsrf, options unless except.include? :json_csrf
|
|
51
|
+
use ::Rack::Protection::PathTraversal, options unless except.include? :path_traversal
|
|
52
|
+
use ::Rack::Protection::RemoteToken, options unless except.include? :remote_token
|
|
53
|
+
use ::Rack::Protection::XSSHeader, options unless except.include? :xss_header
|
|
54
|
+
run app
|
|
55
|
+
end.to_app
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|