许多AJAX请求同时使用CSRF保护

Ede*_*ave 5 javascript php ajax csrf slim

大家好.

我的Web应用程序基于异步请求.定时器小部件正在工作,并且每秒都通过AJAX更新它的状态(是的,这是必要的).

我发送每个AJAX我的CSRF令牌:

project_data.append(csrf_name_key,csrf_name_value);
project_data.append(csrf_value_key,csrf_value_value);
Run Code Online (Sandbox Code Playgroud)

作为回应,我正在更新全局变量:

function setCSRF(response) {
    csrf_name_key = response.nameKey;
    csrf_name_value = response.name;
    csrf_value_key = response.valueKey;
    csrf_value_value = response.value;      
}
Run Code Online (Sandbox Code Playgroud)

一切都很好.但是,如果我将另外的AJAX作为例子,当我将todo列表中的任务更改为"完成"时,它有时会以错误结束,因为我在从前一个请求获取新令牌之前发送AJAX.

我真的不知道如何解决这个问题.第一个想法是我将使用5个不同的令牌制作"像堆栈数组",但是一个https请求=一对令牌,我无法生成它.

也许某种类型的ajax请求队列,但是在适当的时候做什么 - 我不知道.

我的实际伪解决方案是"如果失败再次尝试最多10次":

if(e.target.response=="Failed CSRF check!") {
    if(failedAjax<10) checkForSurvey();
    failedAjax++;
    return;
}
Run Code Online (Sandbox Code Playgroud)

它通常工作,但错误出现在控制台中,这是非常脏的解决方案.

我正在使用带有CSRF扩展的Slim 3微框架.真的请帮助解决这个有趣的问题.

我会非常感激,

亚瑟

jma*_*eis 4

有一些选项供您选择:

  1. 在 JavaScript 代码中使用一堆 csrf-tokens

  2. 使用可以多次使用的 csrf 令牌(不太安全)

  3. 使用队列来处理请求

令牌堆栈

中间件Slim-Csrf为您提供了功能,要生成这些令牌,您只需将它们获取到客户端即可。您可以创建一个获取 5 个 csrf 令牌的 api,该 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);
});
Run Code Online (Sandbox Code Playgroud)

现在,csrf 令牌在整个用户会话中都有效。

Guard::generateToken()返回类似这样的内容:

array (size=2)
  'csrf_name' => string 'csrf58e669ff70da0' (length=17)
  'csrf_value' => string '52ac7689d3c6ea5d01889d711018f058' (length=32)
Run Code Online (Sandbox Code Playgroud)

多用途 csrf 令牌

为此,Slim-Csrf 已经提供了令牌持久化模式的功能。这可以通过构造函数或方法来启用Guard::setPersistentTokenMode(bool)。在我的示例中,我使用以下方法执行此操作:

$container['csrf'] = function ($c) {
    $guard = new \Slim\Csrf\Guard;
    $guard->setPersistentTokenMode(true);
    return $guard;
};
Run Code Online (Sandbox Code Playgroud)

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.
 */
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)