The sec_fetch_site plugin allows for CSRF protection using the Sec-Fetch-Site header added in modern browsers. It allows for CSRF protection without the use of CSRF tokens, which can simplify form creation.
The protection offered by the sec_fetch_site plugin is weaker than the protection offered by the route_csrf plugin with default settings, since it doesn’t support per-request tokens. Be aware you are trading security for simplicity when using the sec_fetch_site plugin instead of the route_csrf plugin. Other caveats in using the sec_fetch_site plugin:
-
Not all browsers set the Sec-Fetch-Site header. Some browsers didn’t start setting the header until 2023. In these cases, you need to decide how to handle the request. The default is to deny the request, though you can use the :allow_missing option to allow it.
-
Sec-Fetch-Site headers are not set for http requests, only https requests, so this doesn’t offer protection for http requests.
-
It isn’t possible to share a CSRF secret between applications in different origins to allow cross-site requests between the applications.
This plugin adds the check_sec_fetch_site! method to the routing block scope. You should call this method at the appropriate place in the routing tree to enforce the CSRF protection. The method can accept a block to override the :csrf_failure plugin option behavior on a per-call basis.
When loading the plugin with no options:
plugin :sec_fetch_site_csrf
Only same-origin requests are allowed by default.
This plugin supports the following options:
| :allow_missing |
Whether to allow requests lacking the Sec-Fetch-Site header (false by default). | ||||||
| :allow_none |
Whether to allow requests where Sec-Fetch-Value is none (false by default). | ||||||
| :allow_same_site |
Whether to allow requests where Sec-Fetch-Value is same-site (false by default) | ||||||
| :check_request_methods |
Which request methods require CSRF protection (default: | ||||||
| :csrf_failure |
The action to taken if a request does not have a valid header (default: :raise). Options:
|
The plugin also supports a block, in which case failures will call the block as a routing block (the block should accept the request object).
Classes and Modules
Constants
| DEFAULTS | = | { :csrf_failure => :raise, :check_request_methods => %w'POST DELETE PATCH PUT'.freeze.each(&:freeze) }.freeze |
Public Class methods
# File lib/roda/plugins/sec_fetch_site_csrf.rb 71 def self.configure(app, opts=OPTS, &block) 72 options = app.opts[:sec_fetch_site_csrf] = (app.opts[:sec_fetch_site_csrf] || DEFAULTS).merge(opts) 73 74 allowed_values = options[:allowed_values] = ["same-origin"] 75 allowed_values << "same-site" if opts[:allow_same_site] 76 allowed_values << "none" if opts[:allow_none] 77 allowed_values << nil if opts[:allow_missing] 78 allowed_values.freeze 79 80 if block 81 options[:csrf_failure] = :method 82 app.define_roda_method(:_roda_sec_fetch_site_csrf_failure, 1, &app.send(:convert_route_block, block)) 83 end 84 85 case options[:csrf_failure] 86 when :raise, :empty_403, :clear_session, :method 87 # nothing 88 else 89 raise RodaError, "Unsupported :csrf_failure plugin option: #{options[:csrf_failure].inspect}" 90 end 91 92 options.freeze 93 end