但是我真的不想仅仅解决这个问题并继续。我真的很想了解真实性令牌。
我的问题是,您是否有关于此主题的完整信息来源,或者您愿意花时间在此处进行详细说明?
#1 楼
当用户查看用于创建,更新或销毁资源的表单时,Rails应用程序会创建一个随机的
authenticity_token
,将该令牌存储在会话中,并将其放置在表单的隐藏字段中。形成。用户提交表单后,Rails会查找authenticity_token
并将其与会话中存储的表单进行比较,如果匹配,则允许继续该请求。为什么会发生
由于真实性令牌存储在会话中,因此客户端无法知道其值。这样可以防止人们在不查看该应用程序本身的形式的情况下将表单提交到Rails应用程序。
想象一下,您正在使用服务A,登录到服务后一切正常。现在,假设您去使用服务B,并且看到了自己喜欢的图片,然后按一下该图片以查看更大的尺寸。现在,如果服务B上存在一些恶意代码,它可能会向服务A(您已登录)发送请求,并通过向
http://serviceA.com/close_account
发送请求来要求删除您的帐户。这就是所谓的CSRF(跨站请求伪造)。如果服务A使用的是真实性令牌,则该攻击向量将不再适用,因为来自服务B的请求将不包含正确的真实性
API文档描述了有关元标记的详细信息:
CS43保护通过
protect_from_forgery
方法打开,/>会检查令牌,如果令牌与期望的会话不匹配,则会重置会话。默认情况下,将为新的Rails应用程序调用此方法。
默认情况下,令牌参数名为
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请求。编辑:检查@erturne关于GET请求是否幂等的评论。他用比我在这里做的更好的方式对其进行了解释。
评论
@Faisal,那么攻击者是否有可能会简单地读取/捕获服务A表单的“隐藏”元素,并获取为用户生成的唯一令牌-假设他们已经获得了由用户启动的会话的访问权限服务A?
– marcamillion
2010-10-25 22:18
@marcamillion:如果有人在服务A劫持了您的会话,那么真实性令牌将无法保护您。劫机者将能够提交请求,并将其继续进行。
–节日
10-10-26在7:02
@zabba:如果提交的表单没有正确的令牌,Rails会引发ActionController :: InvalidAuthenticityToken异常。您可以从异常中抢救并进行所需的任何处理。
–节日
2011年1月31日7:41
“还请确保不要发出任何可能会修改服务器上资源的GET请求。” -这包括在路由中不使用match(),这可能会允许GET请求发送给仅接收POST的控制器操作
–史蒂文·索罗卡(Steven Soroka)
2012年4月25日在18:25
“ ...并且请求应该是幂等的(如果多次运行相同的命令,则每次都应获得相同的结果)。”这里只是一个微妙的澄清。安全意味着没有副作用。幂等意味着相同的副作用,无论调用服务多少次。由于没有副作用,因此所有安全服务本质上都是幂等的。多次在当前时间资源上调用GET每次都会返回不同的结果,但这是安全的(因此是幂等的)。
–erturne
2012年8月18日在16:25
#2 楼
真实性令牌的设计目的是使您知道您的表单是从您的网站提交的。它是由运行它的计算机生成的,具有唯一的标识符,只有您的计算机才能知道它,因此有助于防止跨站点请求伪造攻击。如果您只是在拒绝Rails拒绝AJAX方面遇到困难脚本访问,可以在创建表单时使用
<%= form_authenticity_token %>
生成正确的令牌。
您可以在以下内容中了解更多信息文档。
#3 楼
什么是CSRF?真实性令牌是对跨站请求伪造(CSRF)的对策。您问什么是CSRF?
这是一种攻击者甚至不知道会话令牌就可以劫持会话的方式。
场景:
访问银行的站点,登录。
然后访问攻击者的站点(例如,来自不受信任组织的赞助广告)。 br />攻击者页面中的表单与银行的“转帐资金”表单具有相同的字段。
攻击者知道您的帐户信息,并具有预先填写的表单域,可将资金从您的帐户转移到攻击者的帐户。
攻击者的页面包含将表单提交到您的银行的Javascript。
提交表单时,浏览器会包含您在银行站点的cookie,包括会话令牌。
银行将资金转入攻击者的帐户。
表单可以位于不可见的iframe中,因此您永远不会知道发生了攻击。
这称为跨站请求伪造(CSRF)。
CSRF解决方案:
服务器可以标记来自服务器本身的表单
每个表单都必须包含一个附加的身份验证令牌作为隐藏字段。
令牌必须是不可预测的(攻击者无法猜到)。
服务器在其页面中的表单中提供有效令牌。
服务器在表单发布时检查令牌,拒绝没有适当令牌的表单。
示例令牌:使用服务器密钥加密的会话标识符。
Rails自动生成此类令牌:请参见每种格式的authenticity_token输入字段。
评论
这是相同解释的一个版本,其精确度较低,但摘要也较抽象:stackoverflow.com/a/33829607/2810305
– Lutz Prechelt
2015年11月20日14:59
我不确定,但是,现代浏览器是否允许不将幂等请求(POST / PUT / DELETE)发送到另一个域?我想,在浏览器本身中必须有针对此类情况的保护措施
–divideByZero
16-09-22在20:31
#4 楼
真实性令牌用于防止跨站点请求伪造攻击(CSRF)。要了解真实性令牌,必须首先了解CSRF攻击。CSRF
假设您是
bank.com
的作者。您的网站上有一个表单,该表单用于通过GET请求将资金转至另一个帐户:黑客可以向服务器发送HTTP请求说
GET /transfer?amount=00000&account-to=999999
对吗?错。黑客攻击将无法进行。服务器基本上会考虑吗?
嗯?这个人是谁在尝试发起转移?可以肯定的是,它不是帐户的所有者。
服务器如何知道这一点?因为没有
session_id
cookie来验证请求者。使用用户名和密码登录时,服务器会在浏览器中设置
session_id
cookie。这样,您不必使用用户名和密码对每个请求进行身份验证。当您的浏览器发送session_id
cookie时,服务器会知道:哦,那是John Doe。他于2.5分钟前成功登录。他很好走。
一个黑客可能会认为:
嗯。正常的HTTP请求无法正常工作,但是如果我能亲身体验那个
session_id
cookie,那将是无价之宝。用户浏览器为该浏览器设置了一堆cookie
bank.com
域。每次用户向bank.com
域发出请求时,所有cookie都会一起发送。包括session_id
cookie。因此,如果黑客可以诱使您提出将钱转入他的帐户的GET请求,那么他会成功。
利用跨站点请求伪造。
实际上很简单。黑客可能只是让您访问他的网站。在他的网站上,他可能具有以下图像标签:
<img src="http://bank.com/transfer?amount=00000&account-to=999999">
当用户浏览器遇到该图片标签时,它将向该网址发出GET请求。由于该请求来自他的浏览器,因此它将与
bank.com
关联的所有cookie一起发送。如果用户最近登录过bank.com
...,将设置session_id
cookie,服务器将认为用户打算将$ 1,000,000转移到帐户999999!好吧,只是不要访问危险的地方,您会没事的。
这还不够。如果有人将该图像发布到Facebook并出现在您的墙上怎么办?如果将其注入到您正在通过XSS攻击访问的站点中怎么办?
还不错。只有GET请求容易受到攻击。
不正确。可以动态生成发送POST请求的表单。这是《 Rails安全指南》中的示例:
<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)攻击-就是这样。但这是一天之内的另一种漏洞。
#5 楼
可以防止的最小攻击示例:CSRF在我的网站上
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令牌起作用的原因: />
使用返回表单的GET响应,Rails发送一个很长的随机隐藏参数
,当浏览器发出POST请求时,它会随同发送该参数,而服务器只会接受它如果匹配
,那么真实浏览器上的表单将如下所示:
<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
参数,由于它是一个巨大的随机数,因此我无法猜到它。这种预防技术称为同步器令牌模式。
相同的起源政策
但是什么如果攻击者使用JavaScript发出了两个请求,一个请求读取了令牌,第二个请求进行了传输?
仅同步器令牌模式不足以防止这种情况!
正如我在以下网址中所解释的,这就是“同源起源策略”的解救之道:https://security.stackexchange.com/questions/8264/why-is-the-same-origin-policy-so-important/ 72569#72569
Rails如何发送令牌
覆盖在:Rails:csrf_meta_tag如何工作?
基本:
form_tag
之类的HTML辅助程序会为您的表单添加一个隐藏字段(如果不是GET表单的话)jquery-ujs自动处理AJAX,后者会从
meta
读取令牌由csrf_meta_tags
(在默认模板中显示)添加到标头中的元素,并将其添加到发出的任何请求中。uJS还会尝试以过期的缓存片段形式更新令牌。
其他预防方法
检查是否存在某些标题,例如
X-Requested-With
:X-Requested-With标头的含义是什么?
https://security.stackexchange.com/questions/23371/csrf-protection-with-
X-Requested-With标头服务器检查是否足以保护Ajax驱动的应用程序免受CSRF的侵害?
检查
Origin
标头的值:https://security.stackexchange.com/questions/91165/why-is-the-synchronizer-token-pattern-preferred-over-the-origin-header-check-to重新认证:再次要求用户输入密码。万一您的网站遭到XSSed处理,就应该对每个关键操作(银行登录和汇款,大多数网站的密码更改)都执行此操作。缺点是用户必须多次输入密码,这很麻烦,并且增加了键盘记录/肩膀冲浪的机会。
评论
谢谢,但是关于依靠相同的来源策略不能首先仅读取CSRF令牌的观点似乎存在缺陷。因此,首先您要说您可以发布到不同的来源,但无法读取它,这看起来很奇怪,但我想这是正确的,但是您可以在页面上插入带有get的图像或脚本标签,并链接处理程序以解析响应并得到它吗?
– bjm88
17-2-28在0:29
@ bjm88注入脚本在哪里?在您的网站上还是在受攻击的网站上?如果是受攻击的网站,则允许脚本注入是众所周知的安全漏洞,并有效地典当该网站。每个网站都必须通过输入卫生措施与之抗争。对于图像,我看不到如何将其用于攻击。在攻击网站上:您可以修改浏览器以允许读取,从而随意随意进行典当:-),但是默认情况下不错的浏览器会阻止它,请尝试一下。
– Ciro Santilli郝海东冠状病六四事件法轮功
17-2-28在5:42
#6 楼
为防止“跨站点请求伪造(CSRF或XSRF)攻击”,Authenticity Token
是rails的方法。简单起见,请确保PUT / POST / DELETE(可以修改的方法)内容)对Web应用程序的请求是从客户端的浏览器发出的,而不是从有权访问在客户端创建的Cookie的第三方(攻击者)发出的。
#7 楼
由于Authenticity Token
非常重要,因此在Rails 3.0+中,您可以使用 <%= token_tag nil %>
创建
<input name="authenticity_token" type="hidden" value="token_value">
任何地方
评论
这对我很有帮助。我实际上试图在登录页面上执行XSS,不是出于恶意目的,而是使用预先填写的用户名创建一个新会话。现在我知道我可以只使用value =“ token_value”。
–迈克尔
14年2月24日在16:03
#8 楼
请注意,如果您有来自同一客户端的多个并发请求,那么身份令牌机制可能会导致争用情况。在这种情况下,您的服务器可以在只应有一个真实性令牌的情况下生成多个真实性令牌,并且由于会话cookie令牌已被覆盖,因此以下一个请求形式接收较早令牌的客户端将失败。有一个写操作解决这个问题,并在这里解决一个不完全的问题:
http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
#9 楼
需要authenticity_token
的方法等幂方法(例如post,put和delete)是必需的,因为幂等方法会影响数据。
为什么需要
防止邪恶行为是必须的。 authenticity_token存储在会话中,每当在网页上创建用于创建或更新资源的表单时,就会将真实性令牌存储在隐藏字段中,并将其与服务器上的表单一起发送。在执行操作之前,将使用会话中存储的
authenticity_token
对用户发送的authenticity_token进行交叉检查。如果authenticity_token
是相同的,则过程将继续,否则它将不执行操作。评论
其实不是吗? GET是幂等的,因为它的调用不应更改系统的状态,而PUT POST和DELETE动词不是幂等的动词,因为它们会更改系统状态。 I.E:如果不是NOT幂等方法,则需要authenticity_token。
–让-特奥(Jean-Théo)
2014年7月10日在9:26
@ Jean-Daube,乌干达:幂等的意思是,如果做两次,动作只会发生一次。 GET,PUT和DELETE是幂等的:w3.org/Protocols/rfc2616/rfc2616-sec9.html此处的关键属性不是幂等,但如果方法更改或不更改数据,则称为“安全方法”。
– Ciro Santilli郝海东冠状病六四事件法轮功
2014年11月12日20:14
#10 楼
什么是authentication_token?这是Rails应用程序使用的随机字符串,用于确保用户正在从应用程序页面而不是从另一个应用程序或站点请求或执行操作。
为什么必须要有authentication_token?
要保护您的应用程序或网站免受跨站点伪造的请求。
如何在表单中添加authentication_token?
如果您使用form_for标记生成表单,则会自动添加authentication_token,否则可以使用
<%= csrf_meta_tag %>
。
评论
另请参阅:“为什么Google会将while(1)放在他们的JSON响应前面?” stackoverflow.com/questions/2669690/…