我遇到了一些关于Rails中的真实性令牌的问题,因为我现在已经多次了。
但我真的不想只是解决这个问题而继续下去。我真的很想了解真实性令牌。 那么,我的问题是,您是否有关于此主题的完整信息来源,或者您是否会花时间在此详细解释?
答案 0 :(得分:1414)
会发生什么
当用户查看表单以创建,更新或销毁资源时,Rails应用程序会创建一个随机authenticity_token
,将此标记存储在会话中,并将其放在表单中的隐藏字段中。当用户提交表单时,Rails会查找authenticity_token
,将其与会话中存储的内容进行比较,如果匹配则允许继续。
为什么会发生
由于真实性令牌存储在会话中,因此客户端无法知道其值。这可以防止人们在不查看该应用程序本身内的表单的情况下向Rails应用程序提交表单。
想象一下,您正在使用服务A,您登录该服务,一切正常。现在想象一下你去使用服务B,你看到了你喜欢的图片,并按下图片来查看更大尺寸的图片。现在,如果服务B上有一些恶意代码,它可能会向服务A(您已登录)发送请求,并要求删除您的帐户,方法是向http://serviceA.com/close_account
发送请求。这就是所谓的CSRF (Cross Site Request Forgery)。
如果服务A使用真实性令牌,则此攻击向量不再适用,因为来自服务B的请求将不包含正确的真实性令牌,并且将不允许继续。
API docs描述了有关元标记的详细信息:
使用
protect_from_forgery
方法启用CSRF保护, 它检查令牌并重置会话,如果它不符合什么 预计。为新Rails生成对此方法的调用 应用程序默认情况 token参数默认名为authenticity_token
。名字 必须将此标记的值添加到每个呈现的布局中 通过在HTML头中包含csrf_meta_tags
来形成表单。
备注强>
请记住,Rails只验证非幂等方法(POST,PUT / PATCH和DELETE)。不检查GET请求的真实性令牌。为什么?因为HTTP规范声明GET请求是幂等的,并且应该不创建,更改或销毁服务器上的资源,并且请求应该是幂等的(如果多次运行相同的命令,你应该得到每次都有相同的结果。)
此外,真正的实现在开头定义时要复杂一些,以确保更好的安全性。 Rails不会为每个表单发出相同的存储令牌。它也不是每次都生成和存储不同的令牌。它在会话中生成并存储加密哈希,并发布新的加密令牌,每次呈现页面时,可以与存储的加密令牌进行匹配。请参阅request_forgery_protection.rb。
<强>吸取强>
使用authenticity_token
保护您的非幂等方法(POST,PUT / PATCH和DELETE)。另外,请确保不允许任何可能修改服务器资源的GET请求。
编辑:检查the comment by @erturne有关GET请求是幂等的。他以比我在这里做的更好的方式解释它。
答案 1 :(得分:131)
真品令牌旨在让您知道您的表单是从您的网站提交的。它是从运行它的机器生成的,具有唯一的标识符,只有您的机器可以知道,从而有助于防止跨站点请求伪造攻击。
如果您只是在使用rails拒绝访问AJAX脚本时遇到困难,可以使用
<%= form_authenticity_token %>
在创建表单时生成正确的令牌。
您可以在documentation中了解更多相关信息。
答案 2 :(得分:81)
真实性令牌是跨站请求伪造(CSRF)的对策。你问什么是CSRF?
这是攻击者可能在不知道会话令牌的情况下劫持会话的方式。
<强>方案强>:
CSRF解决方案:
答案 3 :(得分:38)
将被阻止的最小攻击示例
在我的网站evil.com
上,我说服您提交以下表格:
<form action="http://bank.com/transfer" method="post">
<p><input type="hidden" name="to" value="ciro"></p>
<p><input type="hidden" name="ammount" value="100"></p>
<p><button type="submit">CLICK TO GET PRIZE!!!</button></p>
</form>
如果您通过会话cookie登录银行,则会发送cookie并在您不知情的情况下进行转移。
这就是CSRF令牌发挥作用:
因此,真实浏览器上的表单如下所示:
<form action="http://bank.com/transfer" method="post">
<p><input type="hidden" name="authenticity_token" value="j/DcoJ2VZvr7vdf8CHKsvjdlDbmiizaOb5B8DMALg6s=" ></p>
<p><input type="hidden" name="to" value="ciro"></p>
<p><input type="hidden" name="ammount" value="100"></p>
<p><button type="submit">Send 100$ to Ciro.</button></p>
</form>
因此,我的攻击会失败,因为它没有发送authenticity_token
参数,我无法猜到它,因为它是一个巨大的随机数。
此预防技术称为同步器令牌模式。
同步器令牌模式因Same Origin Policy而起作用:如果我可以从evil.com
向您的银行发出XHR GET请求,并且读取结果,我将能够只读取令牌和然后再提出请求。我已在https://security.stackexchange.com/a/72569/53321
我强烈建议您阅读the OWASP guide,关于此问题以及任何其他安全问题。
Rails如何发送令牌
涵盖于:Rails: How Does csrf_meta_tag Work?
基本上:
像form_tag
这样的HTML帮助器为表单添加一个隐藏字段,如果它不是GET表单
AJAX由jquery-ujs自动处理,What's the point of the X-Requested-With header?从meta
添加到标题中的csrf_meta_tags
元素中读取令牌(显示在默认模板中),并添加它可以提出任何要求。
uJS还尝试在过时的缓存片段中更新表单中的令牌。
其他预防方法
X-Requested-With
:
Origin
标题的值:{{3}} 答案 4 :(得分:36)
Authenticity Token
是prevent 'cross-site request forgery (CSRF or XSRF) attacks'的方法。
简单来说,它确保您的Web应用程序的PUT / POST / DELETE(可以修改内容的方法)请求来自客户端的浏览器,而不是来自可以访问的第三方(攻击者)在客户端创建的cookie。
答案 5 :(得分:35)
真实性令牌用于防止跨站点请求伪造攻击(CSRF)。要了解真实性令牌,您必须首先了解CSRF攻击。
假设您是bank.com
的作者。您的网站上有一个表单,用于通过GET请求将资金转移到其他帐户:
黑客可以向服务器发送一条HTTP请求,说GET /transfer?amount=$1000000&account-to=999999
,对吗?
错误。黑客攻击不会起作用。服务器基本上会想到吗?
咦?这个人试图启动转移是谁。它不是帐户的所有者,这是肯定的。
服务器如何知道这一点?因为没有session_id
cookie验证请求者。
当您使用用户名和密码登录时,服务器会在您的浏览器上设置session_id
Cookie。这样,您就不必使用您的用户名和密码对每个请求进行身份验证。当您的浏览器发送session_id
cookie时,服务器知道:
哦,那是John Doe。他在2.5分钟前成功登录。他很高兴。
黑客可能会想:
嗯。普通的HTTP请求无法正常工作,但如果我可以抓住
session_id
Cookie,我就会变得很好。
用户浏览器为bank.com
域设置了一堆Cookie。每次用户向bank.com
域发出请求时,都会发送所有Cookie。包括session_id
Cookie。
因此,如果黑客可以你发出将资金转入其帐户的GET请求,那么他就会成功。他怎么会欺骗你这样做? 使用跨站点请求伪造。
实际上,它非常简单。黑客可以让你访问他的网站。在他的网站上,他可以使用以下图片标记:<img src="http://bank.com/transfer?amount=$1000000&account-to=999999">
当用户浏览器遇到该图片代码时,它会向该网址发出GET请求。由于请求来自他的浏览器,因此它会随身携带与bank.com
相关的所有Cookie。如果用户最近登录了bank.com
...将设置session_id
Cookie,服务器会认为用户打算将1,000,000美元转帐到帐号999999!
好吧,只是不要访问危险的网站,你就没事了。
这还不够。如果有人将该图片发布到Facebook并且它出现在您的墙上会怎么样?如果它被注入您使用XSS攻击访问的网站会怎样?
不是那么糟糕。只有GET请求容易受到攻击。
不正确。可以动态生成发送POST请求的表单。以下是Rails Guide on Security:
中的示例<a href="http://www.harmless.com/" onclick="
var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = 'http://www.example.com/account/destroy';
f.submit();
return false;">To the harmless survey</a>
当ApplicationController
有此时:
protect_from_forgery with: :exception
此:
<%= form_tag do %>
Form contents
<% end %>
编译成:
<form accept-charset="UTF-8" action="/" method="post">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
Form contents
</form>
特别是,生成以下内容:
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
为了防止CSRF攻击,如果Rails没有看到与请求一起发送的真实性令牌,它就不会认为该请求是安全的。
攻击者如何知道这个令牌是什么?每次生成表单时都会随机生成一个不同的值:
跨站点脚本(XSS)攻击 - 这是怎么回事。但这是另一天的不同漏洞。
答案 6 :(得分:32)
因为Authenticity Token
非常重要,而且在Rails 3.0+中你可以使用
<%= token_tag nil %>
创建
<input name="authenticity_token" type="hidden" value="token_value">
的任何地方
答案 7 :(得分:25)
如果您有来自同一客户端的多个并发请求,请注意真实性令牌机制可能会导致竞争条件。在这种情况下,当应该只有一个时,您的服务器可以生成多个真实性令牌,并且在表单中接收先前令牌的客户端将在其下一个请求上失败,因为会话cookie令牌已被覆盖。 有一个关于这个问题的文章,这里有一个不完全简单的解决方案: http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
答案 8 :(得分:8)
需要authenticity_token
的方法
因为幂等方法对数据有影响,因此在post,put和delete等幂等方法的情况下需要
authenticity_token
。
为何需要
需要防止恶行为。 authenticity_token存储在会话中,只要在网页上创建表单以创建或更新资源,则真实性令牌存储在隐藏字段中,并在服务器上与表单一起发送。在执行操作之前,用户发送的authenticity_token与存储在会话中的
authenticity_token
进行交叉检查。如果authenticity_token
相同,则继续处理,否则不执行操作。
答案 9 :(得分:3)
什么是authentication_token?
这是rails应用程序使用的随机字符串,用于确保用户从应用程序页面请求或执行操作,而不是从其他应用程序或站点执行操作。
为什么需要authentication_token?
保护您的应用或网站免受跨网站请求伪造。
如何将authentication_token添加到表单?
如果您使用form_for标记生成表单,则会自动添加authentication_token,否则您可以使用<%= csrf_meta_tag %>
。