iframe 导致 Can't Verify CSRF Token Authenticity n Rails
Posted
技术标签:
【中文标题】iframe 导致 Can\'t Verify CSRF Token Authenticity n Rails【英文标题】:Iframe causes Can't Verify CSRF Token Authenticity n Railsiframe 导致 Can't Verify CSRF Token Authenticity n Rails 【发布时间】:2013-02-20 19:11:20 【问题描述】:我有一个通过 iframe 加载的 webapp,它使用 phonegap 2.3.0 for Windows Phone 8 SDK。通过 iframe 加载它的问题是,当我发送 $.post()
请求时,它会在 Rails 端导致 Can't verify CSRF token authencity
。
我尝试了几种方法,例如覆盖$.post()
以使用$.ajax()
到setHeaderRequest
与令牌,以及$.ajaxSetup()
当我禁用protect_from_forgery
或verify_authenticity_token
时,应用程序会正确加载。
我相信这个问题是因为 webapp 位于另一个域中(跨域问题),而 csrf 只是试图防止点击劫持。有没有办法绕过这个问题?
这是我发布的示例:
$.post(url, app: played: tiles, no: no, function (response)
linkTo('#app_button', response['next']);
);
例子:
$.ajaxSetup(
beforeSend: function(xhr)
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').prop('content'));
);
编辑: 我已经能够将真实性令牌作为参数传递到我的发布请求中,但出现相同的错误。我开始相信错误不是由令牌引起的。发生错误的其他原因是什么?
日志:
[2539 - 2013/03/06 15:37:42] (INFO) Parameters: "app"=>"played"=>"tiles", "no"=>"no", "authenticity_token"=>"yBpUImzjtKGIejh/WCekv/GCi1zjPirib22plqfLJ1Y="
[2539 - 2013/03/06 15:37:42] (WARN) WARNING: Can't verify CSRF token authenticity
[2539 - 2013/03/06 15:37:42] (INFO) User agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)
[2539 - 2013/03/06 15:37:42] (DEBUG) User Load (1.8ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
[2539 - 2013/03/06 15:37:42] (DEBUG) CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
[2539 - 2013/03/06 15:37:42] (DEBUG) CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
[2539 - 2013/03/06 15:37:42] (WARN) Lost session [118.143.97.82] (/locations/1/games) - Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)
[2539 - 2013/03/06 15:37:42] (DEBUG) CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
【问题讨论】:
【参考方案1】:答案是因为没有阻止会话存储的 P3P 标头。您需要添加 P3P 标头来解决此问题。
【讨论】:
有一个 gem 可以让 Rails 发送 P3P 标头:github.com/carrot/p3p【参考方案2】: <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" >
将此隐藏字段添加到您的表单中。我已经修复了类似“无法验证 CSRF 令牌真实性”的问题
【讨论】:
不是表格,而是链接。有没有其他方法可以通过? 这个链接可能对你有帮助***.com/questions/3141041/… Hmm.. 真实性令牌被传递到参数中,但仍然得到相同的错误参数:“app”=>“played”=>“tiles”,“no”= >"no", "authenticity_token"=>"ECVUG1gL8oHzjnlQgR95zxGMlWLvV2x/Ay7UO99LVv0="【参考方案3】:您可以为某些控制器操作关闭 CSRF。您可以为 AJAX 调用创建一个新操作(比如 iframe)并添加到控制器中:
skip_before_filter :verify_authenticity_token, :only => [:iframe]
【讨论】:
【参考方案4】:问题是您需要在 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 不是为了防止点击劫持,它完全是一种单独的攻击,另一个网站可以让用户点击一个链接,该链接通过用户的会话在您的网站上执行操作。
【讨论】:
【参考方案5】:@user1555300 的回答是正确的,只是提供了详细信息。
在application_controller.rb
中添加此内容
before_filter :set_p3p
也加入这个方法
private
# for IE, Facebook, and iframe sessions
def set_p3p
headers['P3P'] = 'CP="ALL DSP COR CURa ADMa DEVa OUR IND COM NAV"'
end
确保这是在 application_controller.rb
而不是常规控制器上。
【讨论】:
以上是关于iframe 导致 Can't Verify CSRF Token Authenticity n Rails的主要内容,如果未能解决你的问题,请参考以下文章
popBackStack 导致 java.lang.IllegalStateException: Can't perform this action after onSaveInstanceState
"for line in..." 导致 UnicodeDecodeError: 'utf-8' codec can't decode byte
尝试运行 svnadmin verify 会导致校验和不匹配