-
Notifications
You must be signed in to change notification settings - Fork 219
/
rack-protection-authenticity-token.html
96 lines (76 loc) · 6.18 KB
/
rack-protection-authenticity-token.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<dl class="rdoc-list note-list"><dt>Prevented attack
<dd>
<p>CSRF</p>
</dd><dt>Supported browsers
<dd>
<p>all</p>
</dd><dt>More infos
<dd>
<p><a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery">en.wikipedia.org/wiki/Cross-site_request_forgery</a></p>
</dd></dl>
<p>This middleware only accepts requests other than <code>GET</code>, <code>HEAD</code>, <code>OPTIONS</code>, <code>TRACE</code> if their given access token matches the token included in the session.</p>
<p>It checks the <code>X-CSRF-Token</code> header and the <code>POST</code> form data.</p>
<p>It is not OOTB-compatible with the <a href="https://rubygems.org/gems/rack_csrf">rack-csrf</a> gem. For that, the following patch needs to be applied:</p>
<pre class="ruby"><span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">Protection</span><span class="ruby-operator">::</span><span class="ruby-constant">AuthenticityToken</span>.<span class="ruby-identifier">default_options</span>(<span class="ruby-value">key:</span> <span class="ruby-string">"csrf.token"</span>, <span class="ruby-value">authenticity_param:</span> <span class="ruby-string">"_csrf"</span>)
</pre>
<h2 id="label-Options">Options<span><a href="#label-Options">¶</a> <a href="#top">↑</a></span></h2>
<dl class="rdoc-list label-list"><dt><code>:authenticity_param</code>
<dd>
<p>the name of the param that should contain the token on a request. Default value: <code>"authenticity_token"</code></p>
</dd><dt><code>:key</code>
<dd>
<p>the name of the param that should contain</p>
<pre>the token in the session. Default value:
<tt>:csrf</tt></pre>
</dd><dt><code>:allow_if</code>
<dd>
<p>a proc for custom allow/deny logic. Default value:</p>
<pre><tt>nil</tt></pre>
</dd></dl>
<h2 id="label-Example-3A+Forms+application">Example: Forms application<span><a href="#label-Example-3A+Forms+application">¶</a> <a href="#top">↑</a></span></h2>
<p>To show what the AuthenticityToken does, this section includes a sample program which shows two forms. One with, and one without a CSRF token The one without CSRF token field will get a 403 Forbidden response.</p>
<p>Install the gem, then run the program:</p>
<pre class="ruby"><span class="ruby-identifier">gem</span> <span class="ruby-identifier">install</span> <span class="ruby-string">'rack-protection'</span>
<span class="ruby-identifier">ruby</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">rb</span>
</pre>
<p>Here is <code>server.rb</code>:</p>
<pre class="ruby"><span class="ruby-identifier">require</span> <span class="ruby-string">'rack/protection'</span>
<span class="ruby-identifier">require</span> <span class="ruby-string">'rack/session'</span>
<span class="ruby-identifier">app</span> = <span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">Builder</span>.<span class="ruby-identifier">app</span> <span class="ruby-keyword">do</span>
<span class="ruby-identifier">use</span> <span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">Session</span><span class="ruby-operator">::</span><span class="ruby-constant">Cookie</span>, <span class="ruby-value">secret:</span> <span class="ruby-string">'secret'</span>
<span class="ruby-identifier">use</span> <span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">Protection</span><span class="ruby-operator">::</span><span class="ruby-constant">AuthenticityToken</span>
<span class="ruby-identifier">run</span> <span class="ruby-operator">-></span> (<span class="ruby-identifier">env</span>) <span class="ruby-keyword">do</span>
[<span class="ruby-value">200</span>, {}, [
<span class="ruby-identifier"><<~EOS</span>
<span class="ruby-value"> <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>rack-protection minimal example</title>
</head>
<body>
<h1>Without Authenticity Token</h1>
<p>This takes you to <tt>Forbidden</tt></p>
<form action="" method="post">
<input type="text" name="foo" />
<input type="submit" />
</form>
<h1>With Authenticity Token</h1>
<p>This successfully takes you to back to this form.</p>
<form action="" method="post">
<input type="hidden" name="authenticity_token" value="#{Rack::Protection::AuthenticityToken.token(env['rack.session'])}" />
<input type="text" name="foo" />
<input type="submit" />
</form>
</body>
</html>
</span><span class="ruby-identifier"> EOS</span>
]]
<span class="ruby-keyword">end</span>
<span class="ruby-keyword">end</span>
<span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">Handler</span><span class="ruby-operator">::</span><span class="ruby-constant">WEBrick</span>.<span class="ruby-identifier">run</span> <span class="ruby-identifier">app</span>
</pre>
<h2 id="label-Example-3A+Customize+which+POST+parameter+holds+the+token">Example: Customize which POST parameter holds the token<span><a href="#label-Example-3A+Customize+which+POST+parameter+holds+the+token">¶</a> <a href="#top">↑</a></span></h2>
<p>To customize the authenticity parameter for form data, use the <code>:authenticity_param</code> option:</p>
<pre class="ruby"><span class="ruby-identifier">use</span> <span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">Protection</span><span class="ruby-operator">::</span><span class="ruby-constant">AuthenticityToken</span>, <span class="ruby-value">authenticity_param:</span> <span class="ruby-string">'your_token_param_name'</span>
</pre>