【问题标题】:CSRF token missing when using Play Framework as an API backend for a Chrome extension使用 Play Framework 作为 Chrome 扩展的 API 后端时缺少 CSRF 令牌
【发布时间】:2018-03-18 20:42:18
【问题描述】:

我有一个项目,其中 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 保护?或者我可以完全禁用它吗?

谢谢,尼尔

【问题讨论】:

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


    【解决方案1】:

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

    1. 手动标记不适用于 CSRF 的路由

    这个很简单。进入您的路由文件并将+ nocsrf 放在您希望免除 CSRF 保护的每条路由上方的行中。当您没有要豁免的一百万个 API 端点或者您没有构建 SPA/公共 API 时,此方法效果最佳。

    1. 配置 CORS

    Set up the CORS filter 接受来自多个域的请求,它会自动绕过 CSRF。

    1. 完全禁用 CSRF

    对于这种用户不直接使用网站的请求,可以假设,如果他们有一个有效的令牌,他们是正确的身份验证,你可以像你建议的那样禁用 CSRF,你会可能没问题。请注意,CSRF 确实使您的应用程序更安全,但仅用于确保无法从其他网站伪造请求。因为看起来您的 API 几乎会从任何地方被调用,所以这不适用于您的项目。但是,如果有的话,我会在后端服务上的任何表单和控件上使用它。

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

    【讨论】:

      【解决方案2】:

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

      如果您提出请求 AJAX,可以在HTML页面中放置CSRF token,然后添加 使用 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"
      })
      

      我希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-10
        • 2017-01-08
        • 2019-06-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-02
        • 1970-01-01
        • 2018-01-19
        相关资源
        最近更新 更多