使用 Play Framework 作为 Chrome 扩展的 API 后端时缺少 CSRF 令牌
CSRF token missing when using Play Framework as an API backend for a Chrome extension
我有一个项目,其中一个 Play Framework 应用程序用作 API 扩展的 Chrome 后端。由于我没有为 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 保护的非常有限的理解,服务器应该在某些时候将 CSRF 令牌包含在某些生成的 HTML 中?但在这种情况下,只有 API 调用 return JSON。我是否希望在来自服务器的 JSON returned 中明确指定 CSRF 令牌,然后手动将其作为 header 包含在 AJAX 调用中 Javascript边?
此外,这种 API 后端是否需要 CSRF 保护?或者我可以完全禁用它吗?
谢谢,尼尔
根据 CSRF filter 的官方文档,几乎所有 non-GET、HEAD 或 OPTIONS 请求(例如 POST 或 PUT)默认启用 CSRF 过滤器其中有某种 cookie/authorization header 并且 CORS 过滤器未配置为信任请求的来源。您有几个选项可以解决此问题:
- 手动标记不适用于 CSRF 的路由
这个很简单。进入你的路由文件,将 + nocsrf
放在你想要免除 CSRF 保护的每条路由上方的行中。当您没有一百万个 API 端点可以豁免或者您没有构建 SPA/public API.
时,此方法效果最佳
- 配置 CORS
Set up the CORS filter 接受来自多个域的请求,它会自动绕过 CSRF。
- 完全禁用 CSRF
对于这种用户没有直接使用网站的请求,可以假设,如果他们有一个有效的令牌,他们被正确地验证了,你可以像你建议的那样禁用 CSRF,然后你可能会没事的。请注意,CSRF 确实使您的应用程序更安全,但只是为了确保不能从另一个网站伪造请求。因为您的 API 似乎会被几乎所有地方调用,所以这不适用于您的项目。但是,如果有的话,我会在后端服务的任何表单和控件上使用它。
编辑: According to this blog,如果你不得不担心 XSS,你仍然应该使用 CSRF。 Token-based 身份验证不受 CSRF 的影响,但如果您不小心,您仍然会受到 XSS 攻击(默认假设是没有人足够小心,并且可以使用一点额外的安全措施)。确保客户端在发出请求时可以获得 CSRF 令牌,并将其与主登录令牌分开存储。然后在服务器上使用两者对请求进行身份验证。
我不喜欢从我的路由中删除 XSS 保护的想法。
The official documentation states :
If you are making requests with
AJAX, you can place the CSRF token in the HTML page, and then add it
to the request using the Csrf-Token header.
我发现 提供了一种将 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"
})
希望对您有所帮助!
我有一个项目,其中一个 Play Framework 应用程序用作 API 扩展的 Chrome 后端。由于我没有为 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 保护的非常有限的理解,服务器应该在某些时候将 CSRF 令牌包含在某些生成的 HTML 中?但在这种情况下,只有 API 调用 return JSON。我是否希望在来自服务器的 JSON returned 中明确指定 CSRF 令牌,然后手动将其作为 header 包含在 AJAX 调用中 Javascript边?
此外,这种 API 后端是否需要 CSRF 保护?或者我可以完全禁用它吗?
谢谢,尼尔
根据 CSRF filter 的官方文档,几乎所有 non-GET、HEAD 或 OPTIONS 请求(例如 POST 或 PUT)默认启用 CSRF 过滤器其中有某种 cookie/authorization header 并且 CORS 过滤器未配置为信任请求的来源。您有几个选项可以解决此问题:
- 手动标记不适用于 CSRF 的路由
这个很简单。进入你的路由文件,将 + nocsrf
放在你想要免除 CSRF 保护的每条路由上方的行中。当您没有一百万个 API 端点可以豁免或者您没有构建 SPA/public API.
- 配置 CORS
Set up the CORS filter 接受来自多个域的请求,它会自动绕过 CSRF。
- 完全禁用 CSRF
对于这种用户没有直接使用网站的请求,可以假设,如果他们有一个有效的令牌,他们被正确地验证了,你可以像你建议的那样禁用 CSRF,然后你可能会没事的。请注意,CSRF 确实使您的应用程序更安全,但只是为了确保不能从另一个网站伪造请求。因为您的 API 似乎会被几乎所有地方调用,所以这不适用于您的项目。但是,如果有的话,我会在后端服务的任何表单和控件上使用它。
编辑: According to this blog,如果你不得不担心 XSS,你仍然应该使用 CSRF。 Token-based 身份验证不受 CSRF 的影响,但如果您不小心,您仍然会受到 XSS 攻击(默认假设是没有人足够小心,并且可以使用一点额外的安全措施)。确保客户端在发出请求时可以获得 CSRF 令牌,并将其与主登录令牌分开存储。然后在服务器上使用两者对请求进行身份验证。
我不喜欢从我的路由中删除 XSS 保护的想法。 The official documentation states :
If you are making requests with AJAX, you can place the CSRF token in the HTML page, and then add it to the request using the Csrf-Token header.
我发现
首先确保将 @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"
})
希望对您有所帮助!