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

时间:2017-04-06 10:43:36

标签: 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);

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

function setCSRF(response) {
    csrf_name_key = response.nameKey;
    csrf_name_value = response.name;
    csrf_value_key = response.valueKey;
    csrf_value_value = response.value;      
}

一切都很好。但是,如果我将todo list中的任务更改为" done"它有时以错误结束,因为我在收到之前请求的新令牌之前发送了AJAX。

我真的不知道如何解决这个问题。第一个想法是,我会像#stack;"有5个不同的令牌,但有一个https请求=一对令牌,我无法生成它。

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

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

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

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

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

我会非常感激,

亚瑟

2 个答案:

答案 0 :(得分:3)

有一些选择:

  1. 在你的javascript代码中使用一堆csrf-tokens

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

  3. 为请求使用队列

  4. 令牌的堆栈

    Slim-Csrf - 中间件为您提供功能,生成这些令牌,您只需将它们带到客户端即可。 你可以用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()会返回如下内容:

    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
        }
    }
    

答案 1 :(得分:0)

通常,您可以通过不接受用于身份验证的Cookie来简单地消除CSRF。

您可以将身份验证令牌保存在localStorage中,并将其作为每个请求的标头发送。

通过这种方式,您永远不必担心CSRF及其令牌。