Rails 3.1 - 忽略 CSRF?
Posted
技术标签:
【中文标题】Rails 3.1 - 忽略 CSRF?【英文标题】:Rails 3.1 - CSRF ignored? 【发布时间】:2011-11-08 09:57:18 【问题描述】:这是我的问题,
我有一个 rails 3.1 应用程序,我正在尝试发出 ajax 请求,但我收到警告消息 “警告:无法验证 CSRF 令牌真实性”...
在我的布局中,我有辅助方法 "csrf_method_tag",我添加了以下 javascript 代码(不知道是否真的需要):
$.ajaxSetup(
beforeSend: function(xhr)
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
);
我的 Gemfile 包含 gem jquery-rails (>= 1.0.12),我需要 jquery 和 jquery-ujs 在我的 application.js 的顶部。
即使这样,消息仍然出现。我是不是忘记了什么?
感谢您的帮助。
【问题讨论】:
有同样的问题 - 登录后,如果我更改页面(使用 devise 和 rpx 可连接 gem),我会注销。如果您解决了这个问题,请告诉我们 在 AJAX 请求的标头中发送的 cookie 是否与在加载发出请求的页面的请求上发送的 cookie 相同? CSRF 令牌与当前会话在交响乐中进行验证,该会话在另一个标头中维护(应该自动发送,但在您的情况下可能不是)。 看我的回答:***.com/questions/15239818/… 【参考方案1】:您可能甚至不需要在代码中使用它。默认情况下,jquery-rails
gem 会自动为所有 Ajax 请求设置 CSRF 令牌。
【讨论】:
我知道,但即使删除了 javascript 代码,CSRF 令牌似乎仍然被忽略... 您是使用标准的railsform_for
和form_tag
助手,还是使用您自己的<form .....>
html 标签?
我没有使用表单...我使用请求来更新部分内容或获取一些 JSON。【参考方案2】:
您是否尝试过使用带有真实性令牌的隐藏表单元素?
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token>" />
我遇到了同样的错误,并且解决了它。这是因为我没有使用内置的表单助手......
【讨论】:
不行,还是不行……我必须在本周末之前解决这个问题,如果我发现了什么,我会告诉你……【参考方案3】:在没有表单的情况下对我有用的是在 ajax 数据负载中包含 <%= form_authenticity_token %>
的结果。所以我做了一些类似 tehprofessor 在 html 中建议的事情:
<input id="tokentag" type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" />
然后在javascript中:
tokentag = $('#tokentag').val()
submitdata = "authenticity_token": tokentag, ...+whatever else you need to include+...
然后用submitdata
调用$.ajax
。
【讨论】:
【参考方案4】:我也遇到了同样的麻烦。我试图捕捉一个 javascript 事件(you_tube 播放器已完成)并将 Ajax 返回到我的服务器让我知道。我得到了:
警告:无法验证 CSRF 令牌的真实性
每当 jQuery ajax 调用访问我的服务器时。我在上面添加了您的代码修复
$.ajaxSetup(
beforeSend: function(xhr)
xhr.setRequestHeader('X-CSRF-Token',
$('meta[name="csrf-token"]').attr('content'));
);
而且效果很好。我认为唯一的区别在于我的布局
<%= csrf_meta_tags %>
而不是您在原始帖子中提到的 csrf_method_tag。 所以谢谢你的修复,它在原始帖子中。
【讨论】:
请不要在你的帖子中使用签名或标语。阅读the FAQ entry了解更多信息。谢谢!【参考方案5】:一个原因可能是您在加载文档之前进行了 AJAX 调用,因此 JQuery 无法获取 CSRF 令牌。
【讨论】:
【参考方案6】:直接在您的 AJAX 调用上执行此操作即可正常工作!
$.ajax(
type: //method,
beforeSend: function(xhr)
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
,
url: //parameter,
dataType: 'html',
success: function(data, textStatus, jqXHR)
// some code
);
【讨论】:
【参考方案7】:问题是您需要在 Ajax POST 请求之后获取新令牌,因为一旦使用令牌,它就会失效。这是执行此操作的代码:
在 Rails 中,每当发送 POST 回复时,将这些参数添加到响应中:
def someMethod:
result[:csrfParam] = request_forgery_protection_token
result[:csrfToken] = form_authenticity_token
render :json => result
end
现在在 JS 端,在每个 POST 方法的成功函数中都可以调用这个函数:
var setCsrfToken = function(param, token)
if(param == null || token == null)
console.error("New CSRF param/token not present");
$("input[name='" + param + "']").val(token);
像这样:
setCsrfToken(result["csrfParam"], result["csrfToken"]);
此函数将重置所有 POST 表单中的所有authentity_token 参数,以便下一个请求具有有效的令牌。您需要确保在每个 POST 调用中都会发生这种情况,否则您将继续面临此问题。
另外,CSRF 不是为了防止点击劫持,它完全是一种单独的攻击,另一个网站可以让用户点击一个链接,该链接通过用户的会话在您的网站上执行操作。
【讨论】:
以上是关于Rails 3.1 - 忽略 CSRF?的主要内容,如果未能解决你的问题,请参考以下文章