大家好.
我的Web应用程序基于异步请求.定时器小部件正在工作,并且每秒都通过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作为例子,当我将todo列表中的任务更改为“完成”时,它有时会以错误结束,因为我在从前一个请求获取新令牌之前发送AJAX.
我真的不知道如何解决这个问题.第一个想法是我将使用5个不同的令牌制作“像堆栈数组”,但是一个https请求=一对令牌,我无法生成它.
也许某种类型的ajax请求队列,但是在适当的时候做什么 – 我不知道.
我的实际伪解决方案是“如果失败再次尝试最多10次”:
if(e.target.response=="Failed CSRF check!") {
if(FailedAjax<10) checkForSurvey();
FailedAjax++;
return;
}
我正在使用带有CSRF扩展的Slim 3微框架.真的请帮助解决这个有趣的问题.
我会非常感激,
亚瑟
>在javascript代码中使用一堆csrf-tokens
>使用可以多次使用的csrf令牌(不太安全)
>为请求使用队列
令牌的堆栈
Slim-Csrf-middleware为您提供功能,生成这些令牌,您只需将它们带到客户端即可.
你可以用api获得5个csrf令牌,这个api也会消耗csrf-token.
$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()返回如下内容:
array (size=2)
'csrf_name' => string 'csrf58e669ff70da0' (length=17)
'csrf_value' => string '52ac7689d3c6ea5d01889d711018f058' (length=32)
多用途csrf令牌
为此,Slim-Csrf已经提供了令牌持久性模式的功能.这可以通过构造函数或Guard :: setPersistentTokenMode(bool)方法启用.在我的例子中,我正在使用该方法:
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard;
$guard->setPersistentTokenMode(true);
return $guard;
};
这里是persistanceTokenMode-attribute的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
}
}