使用Play Framework作为Chrome扩展程序的API后端时,CSRF令牌丢失

时间:2017-10-07 01:56:02

标签: jquery ajax google-chrome-extension playframework csrf-protection

我有一个项目,其中Play Framework应用程序用作Chrome扩展程序的API后端。由于我没有为Play Framework项目指定任何过滤器,因此它默认启用CSRF保护(通过CSRFFilter),这可能适用于我的情况,也可能不适用。

在Chrome扩展程序中,我首先进行jQuery AJAX调用以登录,以便Play Framework服务器设置用户令牌cookie(用于在所有后续API调用中识别用户):

        $.ajax({
        method: 'POST',
        url: serverUrl + "api/google_sign_in",
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify({ google_id_token: token }),
        success: function (response) {
            onSuccess();
        },
        error: function (req, status, error) {
            onError(error);
        }
    });

调用成功,用户令牌设置为cookie。到现在为止还挺好。但是,只要我尝试使用类似的jQuery AJAX调用进行任何其他API调用,Play Framework就会抱怨缺少CSRF令牌,大概是因为现在有一个需要保护的cookie集:

[CSRF] Check failed because no token found in headers for /api/get_status

呼叫失败。根据我对CSRF保护的非常有限的理解,服务器应该在某些时候在某些生成的HTML中包含CSRF令牌?但在这种情况下,只有返回JSON的纯API调用。我是否希望在服务器返回的JSON中明确指定CSRF令牌,然后在Javascript端的以下AJAX调用中手动将其作为标头包含在内?

另外,我是否需要为此类API后端提供CSRF保护?或者我可以完全禁用它吗?

谢谢,Nir

2 个答案:

答案 0 :(得分:1)

根据CSRF filter上的官方文档,默认情况下启用CSRF过滤器几乎任何非GET,HEAD或OPTIONS请求(例如POST或PUT),其中存在某种cookie /授权标头和CORS过滤器未配置为信任请求的来源。您有几个选项可以解决此问题:

  1. 手动标记不适用于CSRF的路线
  2. 这个很容易。进入您的路线文件,并将+ nocsrf放在您想要免除CSRF保护的每条路线上方的行中。当您没有百万个API端点可以免除或者您没有构建SPA /公共API时,这种方法效果最佳。

    1. 配置CORS
    2. Set up the CORS filter接受来自多个域的请求,它将自动绕过CSRF。

      1. 完全禁用CSRF
      2. 对于用户未直接使用网站的此类请求,可以假设,如果他们拥有有效的令牌,他们已经过正确的身份验证,您可以像您建议的那样禁用CSRF,您将会可能没事。请注意,CSRF确实使您的应用程序更安全,但仅限于确保不能从其他网站伪造请求。因为看起来您的API几乎无处不在,所以这不适用于您的项目。但是,如果有任何形式和控件,我会在后端服务上使用它。

        编辑: According to this blog,如果你不得不担心XSS,你仍然应该使用CSRF。基于令牌的身份验证不受CSRF的影响,但如果您不小心,您仍然可能受到XSS的攻击(默认假设是没有人足够小心,并且可以使用一点额外的安全性)。确保客户端在发出请求时可以获取CSRF令牌,并将其与主登录令牌分开存储。然后在服务器上使用两者验证请求。

答案 1 :(得分:0)

我不喜欢从路线中删除XSS保护的想法。 The official documentation states :

  

如果您正在与   AJAX,您可以将CSRF令牌放在HTML页面中,然后添加它   使用Csrf-Token标头访问请求。

我发现this post提供了一种非常不错的方式来将CSRF令牌包含在您的ajax请求中。请务必阅读,因为以下内容仅说明完整答案的表面。

首先,请确保将@AddCSRFToken添加到控制器的方法中,该方法服务于包含发布ajax请求的JS的页面。这样可以从您的JS脚本中使用令牌。

然后在Scala模板(TWIRL)中的脚本中添加以下代码:

<script type="text/javascript">
    $.ajaxSetup({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('Csrf-Token','@helper.CSRF.getToken.value');
        }
    });
</script>

这将告诉JQuery将Csrf令牌传递给您的Ajax请求,并且播放不会干扰。

$.post({
    //Don't forget .url() for the js reverse routing ;)
    url: jsRoutes.controllers.MyController.homePage().url,
    data: {
        armyId : data[i].id,
        position : {   
            x: hex.position.x,
            y: hex.position.y }
        },
    dataType: "json"
})

我希望这对您有帮助!