roda 3.9.0 → 3.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/README.rdoc +43 -23
- data/doc/release_notes/3.10.0.txt +132 -0
- data/lib/roda.rb +3 -3
- data/lib/roda/plugins/assets.rb +2 -2
- data/lib/roda/plugins/flash.rb +8 -2
- data/lib/roda/plugins/json.rb +1 -3
- data/lib/roda/plugins/json_parser.rb +1 -2
- data/lib/roda/plugins/middleware.rb +12 -3
- data/lib/roda/plugins/route_csrf.rb +34 -32
- data/lib/roda/plugins/sessions.rb +451 -0
- data/lib/roda/plugins/typecast_params.rb +15 -2
- data/lib/roda/session_middleware.rb +175 -0
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/csrf_spec.rb +2 -2
- data/spec/plugin/flash_spec.rb +17 -23
- data/spec/plugin/heartbeat_spec.rb +1 -1
- data/spec/plugin/middleware_spec.rb +15 -0
- data/spec/plugin/route_csrf_spec.rb +3 -2
- data/spec/plugin/sessions_spec.rb +371 -0
- data/spec/plugin/typecast_params_spec.rb +11 -0
- data/spec/session_middleware_spec.rb +129 -0
- data/spec/session_spec.rb +2 -2
- data/spec/spec_helper.rb +10 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fa178463d549cd2a8826a8601eccc793e2a3b5a6bb34293ce8511fb8d357128
|
4
|
+
data.tar.gz: 5b099180432b7efc3bc4839883367a454c876d9a2e6809f533f970e83bd32d0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7ec971ff829c784c21c9660b7964f79755841501449c6372260510a367482a9dde5131bf6b488eadefdd24403f7a19576c8d1176d8d8306fecc861388fb9f7f
|
7
|
+
data.tar.gz: 7fe25ba12cceccf1b59d9993d4972c0ffb2df2b78b68716f7708ecc58d131bc0858d9b7a1b87ac34bb88a05b57aeb6f0fb68beac648bbdfe2f7c0c3c6933def9
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
= 3.10.0 (2018-07-18)
|
2
|
+
|
3
|
+
* Remove flash key from session if new flash is empty when rotating flash (jeremyevans)
|
4
|
+
|
5
|
+
* Speed up RodaRequest initialization by avoiding 1-2 method calls (jeremyevans)
|
6
|
+
|
7
|
+
* Add roda/session_middleware (RodaSessionMiddleware), usable as a middleware by any Rack app to use Roda's session support (jeremyevans)
|
8
|
+
|
9
|
+
* Add sessions plugin for more secure (encrypted+signed) sessions (jeremyevans)
|
10
|
+
|
11
|
+
* Support :json_parser and :json_serializer application options as default implementations for parsing/serializing JSON (jeremyevans)
|
12
|
+
|
13
|
+
* Add :handle_result option to middleware plugin for modifying rack result before returning it (jeremyevans)
|
14
|
+
|
15
|
+
* Make the flash plugin work correctly when sessions are serialized with JSON (jeremyevans)
|
16
|
+
|
17
|
+
* Make Integer in typecast_params handle Numeric input, and require that Numeric input not have fractional parts (jeremyevans) (#146)
|
18
|
+
|
1
19
|
= 3.9.0 (2018-06-11)
|
2
20
|
|
3
21
|
* Add route_csrf plugin for CSRF protection, offering more control, better security, and request-specific tokens compared to rack_csrf (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -699,8 +699,15 @@ The following options are respected by the default library or multiple plugins:
|
|
699
699
|
:add_script_name :: Prepend the SCRIPT_NAME for the request to paths. This is
|
700
700
|
useful if you mount the app as a path under another app.
|
701
701
|
:freeze_middleware :: Whether to freeze all middleware when building the rack app.
|
702
|
+
:json_parser :: A callable for parsing JSON (+JSON.parse+ in general used by
|
703
|
+
default).
|
704
|
+
:json_serializer :: A callable for serializing JSON (+to_json+ in general used
|
705
|
+
by default).
|
702
706
|
:root :: Set the root path for the app. This defaults to the current working
|
703
707
|
directory of the process.
|
708
|
+
:sessions_convert_symbols :: This should be set to +true+ if the sessions in use
|
709
|
+
do not support roundtripping of symbols (for
|
710
|
+
example, when sessions are serialized via JSON).
|
704
711
|
|
705
712
|
There may be other options supported by individual plugins, if so it will be
|
706
713
|
mentioned in the documentation for the plugin.
|
@@ -753,38 +760,51 @@ You can override the default rendering options by passing a hash to the plugin:
|
|
753
760
|
template_opts: {default_encoding: 'UTF-8'} # Default template options
|
754
761
|
end
|
755
762
|
|
756
|
-
==
|
763
|
+
== Security
|
764
|
+
|
765
|
+
Web application security is a very large topic,
|
766
|
+
but here are some things you can do with Roda
|
767
|
+
to prevent some common web application vulnerabilities.
|
768
|
+
|
769
|
+
=== Session Security
|
757
770
|
|
758
|
-
By default, Roda doesn't turn on sessions,
|
759
|
-
|
760
|
-
|
761
|
-
that comes with Rack:
|
771
|
+
By default, Roda doesn't turn on sessions, and if you don't need sessions, you can
|
772
|
+
skip this section. If you do need sessions, Roda offers two recommended ways to
|
773
|
+
implement cookie-based sessions.
|
762
774
|
|
763
|
-
|
775
|
+
If you do not need any session support in middleware, and only need session support
|
776
|
+
in the Roda application, then use the sessions plugin:
|
764
777
|
|
778
|
+
require 'roda'
|
765
779
|
class App < Roda
|
766
|
-
|
780
|
+
plugin :sessions, secret: ENV['SESSION_SECRET']
|
767
781
|
end
|
768
782
|
|
769
|
-
|
783
|
+
The +:secret+ option should be a randomly generated string of at least 64 bytes.
|
770
784
|
|
771
|
-
|
772
|
-
|
773
|
-
to prevent some common web application vulnerabilities.
|
785
|
+
If you have middleware that need access to sessions, then use the +RodaSessionMiddleware+
|
786
|
+
that ships with Roda:
|
774
787
|
|
775
|
-
|
788
|
+
require 'roda'
|
789
|
+
require 'roda/session_middleware'
|
790
|
+
class App < Roda
|
791
|
+
use RodaSessionMiddleware, secret: ENV['SESSION_SECRET']
|
792
|
+
end
|
776
793
|
|
777
|
-
If you
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
794
|
+
If you need non-cookie based sessions (such as sessions stored in a database), you
|
795
|
+
should use an appropriate external middleware.
|
796
|
+
|
797
|
+
It is possible to use other session cookie middleware such as
|
798
|
+
<tt>Rack::Session::Cookie</tt>, but other middleware may not have the same security
|
799
|
+
features that Roda's session support does. For example, the session cookies used by
|
800
|
+
the <tt>Rack::Session::Cookie</tt> middleware are not encrypted, just signed to
|
801
|
+
prevent tampering. This means you should not store any secret data in the session
|
802
|
+
when using <tt>Rack::Session::Cookie</tt>.
|
803
|
+
|
804
|
+
For any cookie-based sessions, make sure that the necessary secrets (+:secret+ option)
|
805
|
+
are not disclosed to an attacker. Knowledge of the
|
806
|
+
secret(s) can allow an attacker to inject arbitrary session values. In the case of
|
807
|
+
<tt>Rack::Session::Cookie</tt>, that can also lead remote code execution.
|
788
808
|
|
789
809
|
=== Cross Site Request Forgery (CSRF)
|
790
810
|
|
@@ -0,0 +1,132 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A sessions plugin has been added that supports encrypted and
|
4
|
+
signed sessions. This plugin is now the recommended way to
|
5
|
+
implement sessions, replacing the previously recommended
|
6
|
+
Rack::Session::Cookie middleware.
|
7
|
+
|
8
|
+
The sessions plugin encrypts session data using the AES-256-CTR
|
9
|
+
cipher, and then signs the encrypted data with HMAC-SHA-256. By
|
10
|
+
doing this, attackers must be able to forge a valid HMAC before
|
11
|
+
they can try to exploit possible weaknesses in the encryption,
|
12
|
+
such as timing attacks during decryption that are dependent on
|
13
|
+
attacker chosen initialization vectors or ciphertext.
|
14
|
+
|
15
|
+
In addition to encryption and a stronger default signature
|
16
|
+
algorithm compared to Rack::Session::Cookie, the sessions
|
17
|
+
plugin has the following benefits:
|
18
|
+
|
19
|
+
* Built in session expiration enabeld by default, to mitigate
|
20
|
+
possible session replay issues (default: 30 days since session
|
21
|
+
creation, 7 days since last update).
|
22
|
+
|
23
|
+
* Padding by default to minimize information leakage due to
|
24
|
+
differing session data sizes (session data padded to
|
25
|
+
a multiple of 32 bytes by default before encryption).
|
26
|
+
|
27
|
+
* Automatic deflate compression of large sessions before
|
28
|
+
encryption (by default if session data is over 128 bytes).
|
29
|
+
|
30
|
+
* JSON is used for serialization instead of Marshal, preventing
|
31
|
+
remote code execution vulnerabilities if the session secret
|
32
|
+
is disclosed. Note that this means that many ruby types do not
|
33
|
+
round trip in the session, such as Symbol and Time instances.
|
34
|
+
This will probably be the largest barrier to adoption, as you
|
35
|
+
need to make sure your application only uses types that
|
36
|
+
round-trip through JSON before you start using the sessions
|
37
|
+
plugin.
|
38
|
+
|
39
|
+
* A plain hash is used for the session, instead of a hash-like
|
40
|
+
object. One consequence of this is that keys in the session
|
41
|
+
are not automatically converted to strings.
|
42
|
+
Rack::Session::Cookie converts session keys to strings for
|
43
|
+
keys at the top level, but not for keys in subhashes.
|
44
|
+
|
45
|
+
* In general sessions are smaller even if deflate compression is not
|
46
|
+
used, despite requiring 16 bytes for the cipher initialization
|
47
|
+
vector. The main reason for this is that the sessions plugin does
|
48
|
+
not set a session id, since one is not needed for cookie sessions.
|
49
|
+
|
50
|
+
* The sessions plugin requires a :secret option be set that is
|
51
|
+
at least 64 bytes, so that users have to make a determined
|
52
|
+
effort to use weak secrets.
|
53
|
+
|
54
|
+
* The HMAC calculation considers the cookie key, so that if the
|
55
|
+
same session secret is used for multiple applications with
|
56
|
+
different cookie keys, an attacker cannot use the session from
|
57
|
+
one application in a different application.
|
58
|
+
|
59
|
+
The sessions plugin ties into the Roda#session method instead
|
60
|
+
of being a rack middleware. This makes it about twice as
|
61
|
+
fast as Rack::Session::Cookie if the session is not accessed.
|
62
|
+
If the session is accessed, the sessions plugin is roughly
|
63
|
+
as fast as Rack::Session::Cookie, even though it uses a
|
64
|
+
stronger HMAC and has to encrypt and decrypt the session.
|
65
|
+
|
66
|
+
Because the sessions plugin is not a middleware, it does not
|
67
|
+
offer session support to other middleware, only to the app
|
68
|
+
itself. If you would like to use the same approach as the
|
69
|
+
sessions plugin uses but would like support for middleware to
|
70
|
+
access the sessions, a roda/session_middleware file has been
|
71
|
+
added. This file contains RodaSessionMiddleware, which is a
|
72
|
+
middleware that can be used by any other Rack app for session
|
73
|
+
support, and which uses a SessionHash class similar to the one used
|
74
|
+
by Rack::Session::Cookie.
|
75
|
+
|
76
|
+
To integrate with other plugins that can optionally use symbols
|
77
|
+
or strings in sessions, the sessions plugin sets the
|
78
|
+
:sessions_convert_symbols application option to true. Other plugins
|
79
|
+
can check for this application option, and if set, should use
|
80
|
+
strings instead of symbols in the session.
|
81
|
+
|
82
|
+
The sessions plugin should be loaded after the flash plugin if both
|
83
|
+
are used in the same application, so that the flash is rotated
|
84
|
+
correctly in the session.
|
85
|
+
|
86
|
+
* The middleware plugin now supports a :handle_result option, which
|
87
|
+
can be any callable object. If set, this object is called with the
|
88
|
+
environment of the request and the rack response after either the
|
89
|
+
Roda app or next middleware returns the rack response. The rack
|
90
|
+
response can be modified by the callable object, and the response
|
91
|
+
(after possible modification) will be returned to the previous
|
92
|
+
middleware. Example:
|
93
|
+
|
94
|
+
plugin :middleware, :handle_result=>(proc do |env, res|
|
95
|
+
res[1]['MyHeader'] = 'HeaderValue'
|
96
|
+
end)
|
97
|
+
|
98
|
+
* The :json_parser and :json_serializer application options are now
|
99
|
+
supported. If set, these options are used for parsing and
|
100
|
+
serializing JSON instead of the default of JSON.parse and .to_json.
|
101
|
+
|
102
|
+
= Other Improvements
|
103
|
+
|
104
|
+
* RodaRequest initialization is now faster by avoiding 1-2 method
|
105
|
+
calls.
|
106
|
+
|
107
|
+
* typecast_params.Integer in the typecast_params plugin now handles
|
108
|
+
numeric input as long the numeric input does not have fractional
|
109
|
+
parts. This makes it more usable when handling JSON input.
|
110
|
+
|
111
|
+
* If the flash is empty after the request is processed, the flash
|
112
|
+
session key is removed from the session instead of being left as
|
113
|
+
an empty hash. If addition to making the session smaller, this
|
114
|
+
makes the session appear empty if there are no other keys in the
|
115
|
+
session, which works better with the sessions plugin as empty
|
116
|
+
sessions will remove the session cookie completely.
|
117
|
+
|
118
|
+
= Backwards Compatibility
|
119
|
+
|
120
|
+
* The flash plugin now uses '_flash' instead of :_flash as the session
|
121
|
+
key. When using session middleware that uses
|
122
|
+
Rack::Session::Abstract::SessionHash to store the session (e.g.
|
123
|
+
Rack::Session::Cookie), session keys are converted internally to
|
124
|
+
strings, so this change will not affect you unless you are using
|
125
|
+
alternative session support. Even if your session does treat
|
126
|
+
:_flash different than '_flash' in keys, the plugin will still work
|
127
|
+
because it will try :_flash if there is no value for '_flash'. This
|
128
|
+
change was made to support the sessions plugin, which doesn't
|
129
|
+
convert keys to strings.
|
130
|
+
|
131
|
+
* This DEFAULT_PARSER and DEFAULT_SERIALIZER constants from the
|
132
|
+
the json_parser and json plugins have been removed.
|
data/lib/roda.rb
CHANGED
@@ -228,7 +228,7 @@ class Roda
|
|
228
228
|
# Add a middleware to use for the rack application. Must be
|
229
229
|
# called before calling #route to have an effect. Example:
|
230
230
|
#
|
231
|
-
# Roda.use Rack::
|
231
|
+
# Roda.use Rack::ShowExceptions
|
232
232
|
def use(*args, &block)
|
233
233
|
@middleware << [args, block].freeze
|
234
234
|
build_rack_app
|
@@ -372,7 +372,7 @@ class Roda
|
|
372
372
|
@scope = scope
|
373
373
|
@captures = []
|
374
374
|
@remaining_path = _remaining_path(env)
|
375
|
-
|
375
|
+
@env = env
|
376
376
|
end
|
377
377
|
|
378
378
|
# Handle match block return values. By default, if a string is given
|
@@ -670,7 +670,7 @@ class Roda
|
|
670
670
|
# The session for the current request. Raises a RodaError if
|
671
671
|
# a session handler has not been loaded.
|
672
672
|
def session
|
673
|
-
@env['rack.session'] || raise(RodaError, "You're missing a session handler
|
673
|
+
@env['rack.session'] || raise(RodaError, "You're missing a session handler, try using the sessions plugin.")
|
674
674
|
end
|
675
675
|
|
676
676
|
private
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -368,7 +368,7 @@ class Roda
|
|
368
368
|
|
369
369
|
if opts[:precompiled] && !opts[:compiled] && ::File.exist?(opts[:precompiled])
|
370
370
|
require 'json'
|
371
|
-
opts[:compiled] = ::JSON.parse(::File.read(opts[:precompiled]))
|
371
|
+
opts[:compiled] = (app.opts[:json_parser] || ::JSON.method(:parse)).call(::File.read(opts[:precompiled]))
|
372
372
|
end
|
373
373
|
|
374
374
|
if opts[:early_hints]
|
@@ -451,7 +451,7 @@ class Roda
|
|
451
451
|
if assets_opts[:precompiled]
|
452
452
|
require 'json'
|
453
453
|
::FileUtils.mkdir_p(File.dirname(assets_opts[:precompiled]))
|
454
|
-
::File.open(assets_opts[:precompiled], 'wb'){|f| f.write(assets_opts[:compiled]
|
454
|
+
::File.open(assets_opts[:precompiled], 'wb'){|f| f.write((opts[:json_serializer] || :to_json.to_proc).call(assets_opts[:compiled]))}
|
455
455
|
end
|
456
456
|
|
457
457
|
assets_opts[:compiled]
|
data/lib/roda/plugins/flash.rb
CHANGED
@@ -91,7 +91,8 @@ class Roda
|
|
91
91
|
# Access the flash hash for the current request, loading
|
92
92
|
# it from the session if it is not already loaded.
|
93
93
|
def flash
|
94
|
-
|
94
|
+
# :_flash to support transparent upgrades from previous key
|
95
|
+
@_flash ||= FlashHash.new(session['_flash'] || (session['_flash'] = session.delete(:_flash)))
|
95
96
|
end
|
96
97
|
|
97
98
|
# If the routing doesn't raise an error, rotate the flash
|
@@ -100,7 +101,12 @@ class Roda
|
|
100
101
|
res = super
|
101
102
|
|
102
103
|
if f = @_flash
|
103
|
-
|
104
|
+
f = f.next
|
105
|
+
if f.empty?
|
106
|
+
session.delete('_flash')
|
107
|
+
else
|
108
|
+
session['_flash'] = f
|
109
|
+
end
|
104
110
|
end
|
105
111
|
|
106
112
|
res
|
data/lib/roda/plugins/json.rb
CHANGED
@@ -53,8 +53,6 @@ class Roda
|
|
53
53
|
#
|
54
54
|
# plugin :json, content_type: 'application/xml'
|
55
55
|
module Json
|
56
|
-
DEFAULT_SERIALIZER = :to_json.to_proc
|
57
|
-
|
58
56
|
# Set the classes to automatically convert to JSON, and the serializer to use.
|
59
57
|
def self.configure(app, opts=OPTS)
|
60
58
|
classes = opts[:classes] || [Array, Hash]
|
@@ -63,7 +61,7 @@ class Roda
|
|
63
61
|
app.opts[:json_result_classes].uniq!
|
64
62
|
app.opts[:json_result_classes].freeze
|
65
63
|
|
66
|
-
app.opts[:json_result_serializer] = opts[:serializer] || app.opts[:json_result_serializer] ||
|
64
|
+
app.opts[:json_result_serializer] = opts[:serializer] || app.opts[:json_result_serializer] || app.opts[:json_serializer] || :to_json.to_proc
|
67
65
|
|
68
66
|
app.opts[:json_result_include_request] = opts[:include_request] if opts.has_key?(:include_request)
|
69
67
|
|
@@ -12,7 +12,6 @@ class Roda
|
|
12
12
|
# header for the request includes "json".
|
13
13
|
module JsonParser
|
14
14
|
DEFAULT_ERROR_HANDLER = proc{|r| r.halt [400, {}, []]}
|
15
|
-
DEFAULT_PARSER = JSON.method(:parse)
|
16
15
|
|
17
16
|
# Handle options for the json_parser plugin:
|
18
17
|
# :error_handler :: A proc to call if an exception is raised when
|
@@ -32,7 +31,7 @@ class Roda
|
|
32
31
|
# only wrap values that are not already hashes.
|
33
32
|
def self.configure(app, opts=OPTS)
|
34
33
|
app.opts[:json_parser_error_handler] = opts[:error_handler] || app.opts[:json_parser_error_handler] || DEFAULT_ERROR_HANDLER
|
35
|
-
app.opts[:json_parser_parser] = opts[:parser] || app.opts[:json_parser_parser] ||
|
34
|
+
app.opts[:json_parser_parser] = opts[:parser] || app.opts[:json_parser_parser] || app.opts[:json_parser] || JSON.method(:parse)
|
36
35
|
app.opts[:json_parser_include_request] = opts[:include_request] if opts.has_key?(:include_request)
|
37
36
|
|
38
37
|
case opts[:wrap]
|
@@ -69,10 +69,15 @@ class Roda
|
|
69
69
|
# application that the current request is a middleware request.
|
70
70
|
# You should only need to override this if you are using multiple
|
71
71
|
# roda middleware in the same application.
|
72
|
+
# :handle_result :: Callable object that will be called with request environment
|
73
|
+
# and rack response for all requests passing through the middleware,
|
74
|
+
# after either the middleware or next app handles the request
|
75
|
+
# and returns a response.
|
72
76
|
def self.configure(app, opts={}, &block)
|
73
77
|
app.opts[:middleware_env_var] = opts[:env_var] if opts.has_key?(:env_var)
|
74
78
|
app.opts[:middleware_env_var] ||= 'roda.forward_next'
|
75
79
|
app.opts[:middleware_configure] = block if block
|
80
|
+
app.opts[:middleware_handle_result] = opts[:handle_result]
|
76
81
|
end
|
77
82
|
|
78
83
|
# Forwarder instances are what is actually used as middleware.
|
@@ -102,10 +107,14 @@ class Roda
|
|
102
107
|
end
|
103
108
|
|
104
109
|
if call_next
|
105
|
-
@app.call(env)
|
106
|
-
else
|
107
|
-
res
|
110
|
+
res = @app.call(env)
|
108
111
|
end
|
112
|
+
|
113
|
+
if handle_result = @mid.opts[:middleware_handle_result]
|
114
|
+
handle_result.call(env, res)
|
115
|
+
end
|
116
|
+
|
117
|
+
res
|
109
118
|
end
|
110
119
|
end
|
111
120
|
|
@@ -26,9 +26,11 @@ class Roda
|
|
26
26
|
# sessions, so if the attacker has the ability to read cookie data
|
27
27
|
# and you are using Rack::Session::Cookie, it will still be possible
|
28
28
|
# for an attacker to generate valid CSRF tokens specific to arbitrary
|
29
|
-
# request method and request path.
|
29
|
+
# request method and request path. Roda's session plugin uses
|
30
|
+
# encrypted sessions and therefore is safe even if the attacker can
|
31
|
+
# read cookie data.
|
30
32
|
#
|
31
|
-
#
|
33
|
+
# == Usage
|
32
34
|
#
|
33
35
|
# It is recommended to use the plugin defaults, loading the
|
34
36
|
# plugin with no options:
|
@@ -37,39 +39,39 @@ class Roda
|
|
37
39
|
#
|
38
40
|
# This plugin supports the following options:
|
39
41
|
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
42
|
+
# :field :: Form input parameter name for CSRF token (default: '_csrf')
|
43
|
+
# :header :: HTTP header name for CSRF token (default: 'X-CSRF-Token')
|
44
|
+
# :key :: Session key for CSRF secret (default: '_roda_csrf_secret')
|
45
|
+
# :require_request_specific_tokens :: Whether request-specific tokens are required (default: true).
|
46
|
+
# A false value will allow tokens that are not request-specific
|
47
|
+
# to also work. You should only set this to false if it is
|
48
|
+
# impossible to use request-specific tokens. If you must
|
49
|
+
# use non-request-specific tokens in certain cases, it is best
|
50
|
+
# to leave this option true by default, and override it on a
|
51
|
+
# per call basis in those specific cases.
|
52
|
+
# :csrf_failure :: The action to taken if a request fails the CSRF check (default: :raise). Options:
|
53
|
+
# :raise :: raise a Roda::RodaPlugins::RouteCsrf::InvalidToken exception
|
54
|
+
# :empty_403 :: return a blank 403 page (rack_csrf's default behavior)
|
55
|
+
# :clear_session :: Clear the current session
|
56
|
+
# Proc :: Treated as a routing block, called with request object
|
57
|
+
# :check_header :: Whether the HTTP header should be checked for the token value (default: false).
|
58
|
+
# If true, checks the HTTP header after checking for the form input parameter.
|
59
|
+
# If :only, only checks the HTTP header and doesn't check the form input parameter.
|
60
|
+
# :check_request_methods :: Which request methods require CSRF protection
|
61
|
+
# (default: <tt>['POST', 'DELETE', 'PATCH', 'PUT']</tt>)
|
62
|
+
# :upgrade_from_rack_csrf_key :: If provided, the session key that should be checked for the
|
63
|
+
# rack_csrf raw token. If the session key is present, the value
|
64
|
+
# will be checked against the submitted token, and if it matches,
|
65
|
+
# the CSRF check will be passed. Should only be set temporarily
|
66
|
+
# if upgrading from using rack_csrf to the route_csrf plugin, and
|
67
|
+
# should be removed as soon as you are OK with CSRF forms generated
|
68
|
+
# before the upgrade not longer being usable. The default rack_csrf
|
69
|
+
# key is <tt>'csrf.token'</tt>.
|
68
70
|
#
|
69
71
|
# The plugin also supports a block, in which case the block will be used
|
70
72
|
# as the value of the :csrf_failure option.
|
71
73
|
#
|
72
|
-
#
|
74
|
+
# == Methods
|
73
75
|
#
|
74
76
|
# This adds the following instance methods:
|
75
77
|
#
|
@@ -116,7 +118,7 @@ class Roda
|
|
116
118
|
# will not work unless you set the :require_request_specific_tokens option to
|
117
119
|
# false, which is a bad idea from a security standpoint.
|
118
120
|
#
|
119
|
-
#
|
121
|
+
# == Token Cryptography
|
120
122
|
#
|
121
123
|
# route_csrf uses HMAC-SHA-256 to generate all CSRF tokens. It generates a random 32-byte secret,
|
122
124
|
# which is stored base64 encoded in the session. For each CSRF token, it generates 31 bytes
|