Ajax is losing sessions

◇◆丶佛笑我妖孽 提交于 2019-12-04 03:31:33

问题


I upgraded my Symfony application from Symfony 4.0.7 to Symfony 4.1 and after that AJAX calls are losing sessions values.

I have about 6 ajax requests called at the same time. First of them is going fine but others are losing session values. It happened only after migration to Symfony 4.1 and only for AJAX calls. Any ideas?

edit: It happens only with ajax called at the same time. WHen I add eg 100 miliseconds delay between calling ajax then all works fine.

edit2: it happens on 4 different servers. 2 dev servers, 1 test server and 1 live server. all of them run on NGINX and php7


回答1:


Possible Causes could be, as follows::

Allow to cache requests that use sessions:

Whenever the session is started during a request, Symfony turns the response into a private non-cacheable response to prevent leaking private information. However, even requests making use of the session can be cached under some circumstances.

For example, information related to some user group could be cached for all the users belonging to that group. Handling these advanced caching scenarios is out of the scope of Symfony, but they can be solved with the FOSHttpCacheBundle.

In order to disable the default Symfony behavior that makes requests using the session uncacheable, in Symfony 4.1 we added the NO_AUTO_CACHE_CONTROL_HEADER header that you can add to response:

use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');

Deprecate some uses of Request::getSession()

Using Request::getSession() when no session exists has been deprecated in Symfony 4.1 and it will throw an exception in Symfony 5.0. The solution is to always check first if a session exists with the Request::hasSession() method:

if ($request->hasSession() && ($session = $request->getSession())) {
    $session->set('some_key', 'some_value');
}

More on Ref: Here.




回答2:


Have you check XMLHttpRequest.withCredentials?

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

What about the response Headers?

  1. Access-Control-Allow-Credentials: true
  2. Connection: keep-alive
  3. set-cookie: ...

Are these requests' session id equal?

http://php.net/manual/en/function.session-id.php

Maybe you need set the session cookie before ajax request.

Here is a example:

ajax.php

<?php
function getSessionIdentifier()
{
    if (!session_id()) {
        session_start();
    }
    if (!isset($_SESSION['identifier'])) {
        $_SESSION['identifier'] = bin2hex(random_bytes(5));
    }
    return $_SESSION['identifier'];
}

echo json_encode([
    'identifier' => getSessionIdentifier()
]);

start-without-session.php

<!DOCTYPE html>
<html>
<head><title>start without session</title></head>
<body>
<script>
let started;
const cookie = () => '[' + document.cookie + ']';
const track = () => {
    started = started || (new Date()).getTime();
    return ((new Date()).getTime() - started) + 'ms';
};

const send = (index) => {
    const req = new XMLHttpRequest();
    req.open('GET', '/ajax.php');

    console.log(track(), 'send', index, cookie());

    req.addEventListener("load", () => {
        console.log(track(), 'receive', index, cookie(), req.responseText);
    });

    req.send();
}

document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";

console.log(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.log(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>

start-with-session.php

<?php
session_start();
$_SESSION['identifier'] = bin2hex(random_bytes(5));
?><!DOCTYPE html>
<html>
<head><title>start with session</title></head>
<body>
<script>
let started;
const cookie = () => '[' + document.cookie + ']';
const track = () => {
    started = started || (new Date()).getTime();
    return ((new Date()).getTime() - started) + 'ms';
};

const send = (index) => {
    const req = new XMLHttpRequest();
    req.open('GET', '/ajax.php');

    console.log(track(), 'send', index, cookie());

    req.addEventListener("load", () => {
        console.log(track(), 'receive', index, cookie(), req.responseText);
    });

    req.send();
}

//
// document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
//

console.log(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.log(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>

I'm not 100% sure this is the same situation. need more info.




回答3:


Ok, so the problem was because of session fixation strategy which was changing session ID each request and AJAX requests each after another did have time to update the new ID.

A solution was quite simple, just setting session_fixation_strategy: none.




回答4:


You must not launch all the AJAX requests on the same time when your application depends on live cookies. Maybe the symfony uses something in the cookies to do the CSRF Token work.

The reason why it worked with a 100ms timeout between the request is that the first one had time to parse the response and change the cookies with that response, and the next request used the new cookies.

what you need to do is:

  • make the second AJAX call a callback from the first, the third one a callback from the second and so on...

OR

  • find out what is in the cookies that needs to be up to date to not generate an error and disable it. But take in count that this protection is in place for a reason and you might expose your application to a security breach if disabled. it might help us figuring the issue if you provide the faulty AJAX calls responses (inpect->network in browser)

OR

  • Make your ajax call use JWT based middleware (witch is complicated if you never done it before) so it uses a stateless session.


来源:https://stackoverflow.com/questions/50925212/ajax-is-losing-sessions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!