首页 文章

理解Rails真实性令牌

提问于
浏览
900

我正在遇到有关Rails中的Authenticity Token的一些问题,因为我现在已经多次了 .

但我真的不想只是解决这个问题而继续下去 . 我真的很想了解真实性令牌 . 那么,我的问题是,您是否有关于此主题的完整信息来源,或者您是否会花时间在此详细解释?

10 回答

  • 1387

    如果您有来自同一客户端的多个并发请求,请注意真实性令牌机制可能会导致竞争条件 . 在这种情况下,当应该只有一个时,您的服务器可以生成多个真实性令牌,并且在表单中接收先前令牌的客户端将在其下一个请求上失败,因为会话cookie令牌已被覆盖 . 有一个关于这个问题的文章,这里有一个不完全简单的解决方案:http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/

  • 38

    因为 Authenticity Token 非常重要,而且在Rails 3.0中你可以使用

    <%= token_tag nil %>
    

    创造

    <input name="authenticity_token" type="hidden" value="token_value">
    

    随地

  • 3

    What is an authentication_token ?

    这是rails应用程序使用的随机字符串,用于确保用户从应用程序页面请求或执行操作,而不是从其他应用程序或站点执行操作 .

    Why is an authentication_token is necessary ?

    保护您的应用或网站免受跨网站请求伪造 .

    How to add an authentication_token to a form ?

    如果使用form_for标记生成表单,则会自动添加authentication_token,否则可以使用 <%= csrf_meta_tag %> .

  • 28

    What happens

    当用户查看表单以创建,更新或销毁资源时,Rails应用程序会创建一个随机的 authenticity_token ,将此令牌存储在会话中,并将其放在表单中的隐藏字段中 . 当用户提交表单时,Rails会查找 authenticity_token ,将其与会话中存储的那个进行比较,如果匹配,则允许继续请求 .

    Why it happens

    由于真实性令牌存储在会话中,因此客户端无法知道其值 . 这可以防止人们在不查看该应用程序本身内的表单的情况下向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,将此标记的名称和值添加到呈现表单的每个布局中 .

    Notes

    请记住,Rails只验证非幂等方法(POST,PUT / PATCH和DELETE) . 不检查GET请求的真实性令牌 . 为什么?因为HTTP规范声明GET请求是幂等的,并且应该在服务器上创建,更改或销毁资源,并且请求应该是幂等的(如果多次运行相同的命令,则每次都应该获得相同的结果) .

    此外,真正的实现在开始时定义更复杂,确保更好的安全性 . Rails不会为每个表单发出相同的存储令牌 . 它也不是每次都生成和存储不同的令牌 . 它在会话中生成并存储加密哈希,并发布新的加密令牌,每次呈现页面时,可以与存储的加密令牌进行匹配 . 见request_forgery_protection.rb .

    Lessons

    使用 authenticity_token 保护您的非幂等方法(POST,PUT / PATCH和DELETE) . 还要确保不允许任何可能修改服务器资源的GET请求 .


    EDIT: 检查the comment by @erturne,关于GET请求是幂等的 . 他以比我在这里做的更好的方式解释它 .

  • 80

    什么是CSRF?

    真实性令牌是跨站请求伪造(CSRF)的对策 . 你问什么是CSRF?

    这是攻击者可能在不知道会话令牌的情况下劫持会话的方式 .

    Scenario

    • 访问您银行的网站,登录 .

    • 然后访问攻击者的网站(例如来自不受信任的组织的赞助广告) .

    • 攻击者's page includes form with same fields as the bank' s "Transfer Funds"表格 .

    • 攻击者知道您的帐户信息,并预先填写了表单字段,以便将资金从您的帐户转移到攻击者的帐户 .

    • 攻击者的页面包含向您的银行提交表单的Javascript .

    • 表单提交后,浏览器会包含您的银行网站的Cookie,包括会话令牌 .

    • 银行将钱转移到攻击者的帐户 .

    • 表单可以在不可见的iframe中,因此您永远不会知道发生了攻击 .

    • 这称为跨站请求伪造(CSRF) .

    CSRF solution

    • 服务器可以标记来自服务器本身的表单

    • 每个表单必须包含一个额外的身份验证令牌作为隐藏字段 .

    • 令牌必须是不可预测的(攻击者无法猜测) .

    • Server提供有效令牌在其页面中的表单中 .

    • 服务器在发布表单时检查令牌,拒绝没有正确令牌的表单 .

    • 示例令牌:使用服务器密钥加密的会话标识符 .

    • Rails自动生成此类标记:请参阅每个表单中的authenticity_token输入字段 .

  • 8

    Authenticity Token 是rails的方法prevent 'cross-site request forgery (CSRF or XSRF) attacks' .

    简单来说,它确保您的Web应用程序的PUT / POST / DELETE(可以修改内容的方法)请求来自客户端的浏览器,而不是来自可以访问cookie的第三方(攻击者)在客户端 .

  • 130

    Methods Where authenticity_token is required

    ifmpotent方法(如post,put和delete)需要authenticity_token,因为Idempotent方法会影响数据 .

    Why It is Required

    需要防止邪恶行为 . authenticity_token存储在会话中,只要在网页上创建表单以创建或更新资源,就会将真实性令牌存储在隐藏字段中,并将其与表单一起发送到服务器上 . 在执行操作之前,用户发送的authenticity_token与存储在会话中的authenticity_token进行交叉检查 . 如果authenticity_token相同则继续进程,否则它不执行操作 .

  • 35

    真实性令牌用于防止跨站请求伪造攻击(CSRF) . 要了解真实性令牌,您必须首先了解CSRF攻击 .

    CSRF

    假设您是 bank.com 的作者 . 您的网站上有一个表单,用于通过GET请求将资金转帐到其他帐户:

    enter image description here

    黑客可以向服务器发送HTTP请求,说 GET /transfer?amount=$1000000&account-to=999999 ,对吧?

    enter image description here

    错误 . 黑客攻击不起作用 . 服务器基本上会想到吗?

    嗯?这个人试图启动转移是谁 . 它不是帐户的所有者,这是肯定的 .

    服务器如何知道这一点?因为没有 session_id cookie验证请求者 .

    当您使用用户名和密码登录时,服务器会在您的浏览器上设置 session_id cookie . 这样,您就不必使用您的用户名和密码验证每个请求 . 当您的浏览器发送 session_id cookie时,服务器知道:

    哦,那是John Doe . 他在2.5分钟前成功登录 . 他很高兴 .

    黑客可能会想:

    嗯 . 普通的HTTP请求不起作用,但是如果我可以 grab 那个session_id cookie,那我就是金色的 .

    用户浏览器为 bank.com 域设置了一堆cookie . 每次用户向 bank.com 域发出请求时,都会发送所有cookie . 包括 session_id cookie .

    因此,如果黑客能够让你做出将资金转入他账户的GET请求,他就会成功 . 他怎么会欺骗你这样做?使用跨站点请求伪造 .

    实际上,它非常简单 . 黑客可以让你访问他的网站 . 在他的网站上,他可以有以下图片标签:

    <img src="http://bank.com/transfer?amount=$1000000&account-to=999999">
    

    当用户浏览器遇到该图像标记时,它会发送与 bank.com 相关的所有cookie . 如果用户最近已登录 bank.com ...将设置 session_id cookie,服务器将认为用户打算将$ 1,000,000转移到帐户999999!

    enter image description here

    好吧,只是不要访问危险的网站,你会没事的 .

    这还不够 . 如果有人将该图片发布到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="&#x2713;" />
      <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
      Form contents
    </form>
    

    特别是,生成以下内容:

    <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
    

    为了防止CSRF攻击,如果Rails没有看到与请求一起发送的真实性令牌,它将不会认为请求是安全的 .

    攻击者如何知道这个令牌是什么?每次生成表单时都会随机生成一个不同的值:

    enter image description here

    跨站点脚本(XSS)攻击 - 就是这样 . 但这是另一天的不同漏洞 .

  • 32

    Minimal attack example that would be prevented

    在我的网站 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 参数,我无法猜到它,因为它是一个巨大的随机数 .

    这种预防技术称为 Synchronizer Token Pattern .

    同步器令牌模式因Same Origin Policy而起作用:如果我可以从 evil.com 向您的银行发出XHR GET请求,并且读取结果,我将能够只读取令牌然后再发出请求 . 我在下面进一步解释了这个问题:https://security.stackexchange.com/a/72569/53321

    我强烈建议您阅读the OWASP guide,关于此问题以及任何其他安全问题 .

    How Rails sends the tokens

    涵盖于:Rails: How Does csrf_meta_tag Work?

    基本上:

    • HTML帮助器如 form_tag 如果它不是GET表单,则为表单添加一个隐藏字段

    • AJAX由jquery-ujs自动处理,它从 csrf_meta_tags (存在于默认模板中)中添加到 Headers 的 meta 元素中读取标记,并将其添加到任何请求中 .

    uJS还尝试在过时的缓存片段中更新表单中的标记 .

    Other prevention approaches

  • 25

    真品令牌旨在让您知道您的表单是从您的网站提交的 . 它是从运行它的机器生成的,具有唯一的标识符,只有您的机器才能知道,从而有助于防止跨站点请求伪造攻击 .

    如果您只是在使用rails拒绝AJAX脚本访问时遇到困难,可以使用

    <%= form_authenticity_token %>
    

    在创建表单时生成正确的标记 .

    您可以在documentation中阅读更多相关信息 .

相关问题