许多 AJAX 请求同时具有 CSRF 保护
Many AJAX requests at once with CSRF protection
大家好
我的网络应用程序是基于异步请求的。计时器小部件正在工作并每秒更新一次状态 AJAX(是的,这是必要的)。
我正在发送每个 AJAX 我的 CSRF 令牌:
project_data.append(csrf_name_key,csrf_name_value);
project_data.append(csrf_value_key,csrf_value_value);
作为回应,我正在更新全局变量:
function setCSRF(response) {
csrf_name_key = response.nameKey;
csrf_name_value = response.name;
csrf_value_key = response.valueKey;
csrf_value_value = response.value;
}
一切都很好。但是,如果我将执行另一个 AJAX,例如当我将待办事项列表中的任务更改为 "done" 时,它有时会以错误结束,因为我在从之前的请求中获取新令牌之前发送了 AJAX。
我真的不知道如何解决这个问题。第一个想法是,我将使用 5 个不同的令牌制作 "like stack array",但一个 https 请求 = 一对令牌,但我无法生成它。
也许是某种类型的 ajax 请求队列,但是在正确的时间执行它们会怎样 - 我不知道。
我实际的伪解是"if failed try again max 10 times":
if(e.target.response=="Failed CSRF check!") {
if(failedAjax<10) checkForSurvey();
failedAjax++;
return;
}
它通常可以工作,但控制台中会出现错误,这是非常肮脏的解决方案。
我正在使用带有 CSRF 扩展的 Slim 3 微框架。真的请帮助解决这个有趣的问题。
我会很感激的,
亚瑟
通常,您可以通过不接受用于身份验证的 cookie 来简单地消除 CSRF。
您可以将身份验证令牌保存在 localStorage 中,并在每次请求时将其作为 header 发送。
这样你就永远不需要担心 CSRF 及其令牌。
有一些选项供您选择:
在你体内使用一堆 csrf-tokens javascript 代码
使用可以多次使用的 csrf 令牌(不太安全)
为请求使用队列
令牌堆栈
Slim-Csrf
-middleware 为您提供了功能,要生成这些令牌,您只需要将它们发送到客户端即可。
你可以做一个 api 来获得 5 个 csrf 令牌,这个 api 也会消耗 csrf-token。
添加一个 api 并在那里生成令牌。
$app->get('/foo', function ($request, $response, $args) {
// check valid csrf token
$tokens = [];
for ($i = 0; $i < 5; $i++) {
$tokens[] = $this->csrf->generateToken();
}
return $response->withJson($tokens);
});
现在 csrf-token 在整个用户会话期间都有效。
Guard::generateToken()
returns 像这样:
array (size=2)
'csrf_name' => string 'csrf58e669ff70da0' (length=17)
'csrf_value' => string '52ac7689d3c6ea5d01889d711018f058' (length=32)
一个多用途的 csrf-token
为此,Slim-Csrf 已经提供了令牌持久模式的功能。这可以通过构造函数或 Guard::setPersistentTokenMode(bool)
方法启用。在我的示例中,我使用以下方法执行此操作:
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard;
$guard->setPersistentTokenMode(true);
return $guard;
};
这里是来自 persistanceTokenMode
-属性
的 PhpDoc
/**
* Determines whether or not we should persist the token throughout the duration of the user's session.
*
* For security, Slim-Csrf will *always* reset the token if there is a validation error.
* @var bool True to use the same token throughout the session (unless there is a validation error),
* false to get a new token with each request.
*/
ajax 个请求的队列。
为请求添加一个队列,这可能会延迟请求的执行,但始终会有一个有效的 csrf 令牌。
这应该被视为伪代码,因为我还没有测试过它。
var requestQueue = [];
var isInRequest = false;
var csrfKey = ''; // should be set on page load, to have a valid token at the start
var csrfValue = '';
function newRequest(onSuccessCallback, data) { // add all parameters you need
// add request to the queue
requestQueue.push(function() {
isInRequest = true;
// add to csrf stuff to data
$.ajax({
data: xxx
url: "serverscript.xxx",
success: function(data) {
// update csrfKey & csrfValue
isInRequest = false;
tryExecuteNextRequest(); // try execute next request
onSuccessCallback(data); // proceed received data
}
}});
);
tryExecuteNextRequest();
}
function tryExecuteNextRequest() {
if(!isInRequest && requestQueue.length != 0) { // currently no request running &
var nextRequest = requestQueue.shift();
nextRequest(); // execute next request
}
}
大家好
我的网络应用程序是基于异步请求的。计时器小部件正在工作并每秒更新一次状态 AJAX(是的,这是必要的)。
我正在发送每个 AJAX 我的 CSRF 令牌:
project_data.append(csrf_name_key,csrf_name_value);
project_data.append(csrf_value_key,csrf_value_value);
作为回应,我正在更新全局变量:
function setCSRF(response) {
csrf_name_key = response.nameKey;
csrf_name_value = response.name;
csrf_value_key = response.valueKey;
csrf_value_value = response.value;
}
一切都很好。但是,如果我将执行另一个 AJAX,例如当我将待办事项列表中的任务更改为 "done" 时,它有时会以错误结束,因为我在从之前的请求中获取新令牌之前发送了 AJAX。
我真的不知道如何解决这个问题。第一个想法是,我将使用 5 个不同的令牌制作 "like stack array",但一个 https 请求 = 一对令牌,但我无法生成它。
也许是某种类型的 ajax 请求队列,但是在正确的时间执行它们会怎样 - 我不知道。
我实际的伪解是"if failed try again max 10 times":
if(e.target.response=="Failed CSRF check!") {
if(failedAjax<10) checkForSurvey();
failedAjax++;
return;
}
它通常可以工作,但控制台中会出现错误,这是非常肮脏的解决方案。
我正在使用带有 CSRF 扩展的 Slim 3 微框架。真的请帮助解决这个有趣的问题。
我会很感激的,
亚瑟
通常,您可以通过不接受用于身份验证的 cookie 来简单地消除 CSRF。
您可以将身份验证令牌保存在 localStorage 中,并在每次请求时将其作为 header 发送。
这样你就永远不需要担心 CSRF 及其令牌。
有一些选项供您选择:
在你体内使用一堆 csrf-tokens javascript 代码
使用可以多次使用的 csrf 令牌(不太安全)
为请求使用队列
令牌堆栈
Slim-Csrf
-middleware 为您提供了功能,要生成这些令牌,您只需要将它们发送到客户端即可。
你可以做一个 api 来获得 5 个 csrf 令牌,这个 api 也会消耗 csrf-token。
添加一个 api 并在那里生成令牌。
$app->get('/foo', function ($request, $response, $args) {
// check valid csrf token
$tokens = [];
for ($i = 0; $i < 5; $i++) {
$tokens[] = $this->csrf->generateToken();
}
return $response->withJson($tokens);
});
现在 csrf-token 在整个用户会话期间都有效。
Guard::generateToken()
returns 像这样:
array (size=2)
'csrf_name' => string 'csrf58e669ff70da0' (length=17)
'csrf_value' => string '52ac7689d3c6ea5d01889d711018f058' (length=32)
一个多用途的 csrf-token
为此,Slim-Csrf 已经提供了令牌持久模式的功能。这可以通过构造函数或 Guard::setPersistentTokenMode(bool)
方法启用。在我的示例中,我使用以下方法执行此操作:
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard;
$guard->setPersistentTokenMode(true);
return $guard;
};
这里是来自 persistanceTokenMode
-属性
/**
* Determines whether or not we should persist the token throughout the duration of the user's session.
*
* For security, Slim-Csrf will *always* reset the token if there is a validation error.
* @var bool True to use the same token throughout the session (unless there is a validation error),
* false to get a new token with each request.
*/
ajax 个请求的队列。
为请求添加一个队列,这可能会延迟请求的执行,但始终会有一个有效的 csrf 令牌。
这应该被视为伪代码,因为我还没有测试过它。
var requestQueue = [];
var isInRequest = false;
var csrfKey = ''; // should be set on page load, to have a valid token at the start
var csrfValue = '';
function newRequest(onSuccessCallback, data) { // add all parameters you need
// add request to the queue
requestQueue.push(function() {
isInRequest = true;
// add to csrf stuff to data
$.ajax({
data: xxx
url: "serverscript.xxx",
success: function(data) {
// update csrfKey & csrfValue
isInRequest = false;
tryExecuteNextRequest(); // try execute next request
onSuccessCallback(data); // proceed received data
}
}});
);
tryExecuteNextRequest();
}
function tryExecuteNextRequest() {
if(!isInRequest && requestQueue.length != 0) { // currently no request running &
var nextRequest = requestQueue.shift();
nextRequest(); // execute next request
}
}