Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Session cookies are sent twice with Ajax #6166

Closed
kenjis opened this issue Jun 20, 2022 · 9 comments · Fixed by #6167
Closed

Bug: Session cookies are sent twice with Ajax #6166

kenjis opened this issue Jun 20, 2022 · 9 comments · Fixed by #6167
Labels
bug Verified issues on the current code behavior or pull requests that will fix them

Comments

@kenjis
Copy link
Member

kenjis commented Jun 20, 2022

v4.2.0

  • Session cookies are sent twice when regenerating session
  • The old session cookie is sent after new session cookie

See #5656 (comment)

@kenjis kenjis added the bug Verified issues on the current code behavior or pull requests that will fix them label Jun 20, 2022
@skuadron45
Copy link

skuadron45 commented Jun 20, 2022

PHP Version: 7.4.19
Apache:
gambar

I have created repo for test this issue at https://github.com/skuadron45/ajaxmythauth

Links:
https://bugs.php.net/bug.php?id=75554
https://stackoverflow.com/questions/55754652/session-regenerate-id-causes-two-phpsessid-cookies-to-be-returned

What have i done for resolve this issue:

Routes:

$routes->get('test', function () {

    $oldSession  = session()->session_id;

    $oldData = session()->get();
    session()->regenerate();

    $newSession = session()->session_id;
    $newData = session()->get();
    return json_encode([
        'old' => $oldSession,
        'old_data' => $oldData,
        'new' => $newSession,
        'new_data' => $newData
    ]);
});

Result for Set Cookie on Response Header when i request it with browser
gambar

Result for Set Cookie on Response Header when i request it with curl is sent twice but the order for Set Cookie was same for old and new

C:\Users\Andia>curl -sv http://ajaxmythauth.test/test
*   Trying 127.0.0.1:80...
* Connected to ajaxmythauth.test (127.0.0.1) port 80 (#0)
> GET /test HTTP/1.1
> Host: ajaxmythauth.test
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Mon, 20 Jun 2022 22:41:17 GMT
< Server: Apache/2.4.47 (Win64) OpenSSL/1.1.1k PHP/7.4.19
< X-Powered-By: PHP/7.4.19
< Set-Cookie: ci_session_=j8f34bkl98mv74jtbomnk6da5cksnvmh; expires=Tue, 21-Jun-2022 00:41:18 GMT; Max-Age=7200; path=/; HttpOnly; SameSite=Lax
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Set-Cookie: ci_session_=3gh65tks4bms7soas4rqas5jtds5doi6; expires=Tue, 21-Jun-2022 00:41:18 GMT; Max-Age=7200; path=/; HttpOnly; SameSite=Lax
< Cache-control: no-store, max-age=0, no-cache
< Content-Length: 177
< Content-Type: text/html; charset=UTF-8
<
{"old":"j8f34bkl98mv74jtbomnk6da5cksnvmh","old_data":{"__ci_last_regenerate":1655764878},"new":"3gh65tks4bms7soas4rqas5jtds5doi6","new_data":{"__ci_last_regenerate":1655764878}}* Connection #0 to host ajaxmythauth.test left intact

C:\Users\Andia>

Result for Set Cookie on Response Header when i request it with ajax jquery on browser.
gambar

As you can see on above, if i request it with curl and jquery ajax, Set Cookie was sent twice in my environment.
The different only for ordering in Set Cookie.

I will try to change my Apache to know about bug issue on Apache related to this statement

RFC: https://tools.ietf.org/html/rfc6265#section-4.1.1
"Servers SHOULD NOT include more than one Set-Cookie header field in the same response with the same cookie-name.  (See Section 5.2 for how user agents handle this case.)"

Thanks

@skuadron45
Copy link

skuadron45 commented Jun 20, 2022

Workaround solution from me for ajax request:

$routes->get('test', function () {

    $oldSession  = session()->session_id;

    $oldData = session()->get();
    session()->regenerate();

    $newSession = session()->session_id;
    $newData = session()->get();

    Services::response()->getCookieStore()->clear(); //add this line
    return json_encode([
        'old' => $oldSession,
        'old_data' => $oldData,
        'new' => $newSession,
        'new_data' => $newData
    ]);
});

and the result was only one Set Cookie for the new session id

gambar

I hope i can know if this issue was bug for my Apache or in CI, because after this commit about cookie send on response, the ordering of Set Cookie was changed.

@skuadron45
Copy link

comment if you have some issue like me if using ajax only

@kenjis
Copy link
Member Author

kenjis commented Jun 21, 2022

I reproduced this bug.

$routes->get('test', static function () {
    $oldSession = session()->session_id;

    $oldData = session()->get();
    session()->regenerate();

    $newSession = session()->session_id;
    $newData = session()->get();

    return json_encode([
        'old'      => $oldSession,
        'old_data' => $oldData,
        'new'      => $newSession,
        'new_data' => $newData,
    ]);
});

Send the following request more than once.

$ curl -v -c cookiejar -b cookiejar -H 'X-Requested-With: xmlhttprequest' http://localhost:8080/test
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Cookie: ci_session=kcsk74kjdslm0nsv69f9h57kl920gbhj
> X-Requested-With: xmlhttprequest
> 
< HTTP/1.1 200 OK
< Host: localhost:8080
< Date: Tue, 21 Jun 2022 07:43:00 GMT
< Connection: close
< X-Powered-By: PHP/8.0.20
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
* Replaced cookie ci_session="c4hq1solt7gjhsl3vekoaevmon6p8sga" for domain localhost, path /, expire 1655804580
< Set-Cookie: ci_session=c4hq1solt7gjhsl3vekoaevmon6p8sga; expires=Tue, 21-Jun-2022 09:43:00 GMT; Max-Age=7200; path=/; HttpOnly; SameSite=Lax
< Cache-control: no-store, max-age=0, no-cache
< Content-Type: text/html; charset=UTF-8
< Debugbar-Time: 1655797380.056830
< Debugbar-Link: http://localhost:8080/index.php?debugbar_time=1655797380.056830
* Replaced cookie ci_session="kcsk74kjdslm0nsv69f9h57kl920gbhj" for domain localhost, path /, expire 1655804580
< Set-Cookie: ci_session=kcsk74kjdslm0nsv69f9h57kl920gbhj; expires=Tue, 21-Jun-2022 09:43:00 GMT; Max-Age=7200; path=/; HttpOnly; SameSite=Lax
< 
* Closing connection 0
{"old":"kcsk74kjdslm0nsv69f9h57kl920gbhj","old_data":{"__ci_last_regenerate":1655797370},"new":"c4hq1solt7gjhsl3vekoaevmon6p8sga","new_data":{"__ci_last_regenerate":1655797380}}

@kenjis kenjis changed the title Bug: Session cookies are sent twice Bug: Session cookies are sent twice with Ajax Jun 21, 2022
@kenjis
Copy link
Member Author

kenjis commented Jun 21, 2022

This bug is because of the setCookie() in line 255.
The line runs only in Ajax requests. But it seems it is not necessary...
If the session cookie is sent to the server, the client has already the session cookie.
Why do we need to send it again only in Ajax requests?

// Is session ID auto-regeneration configured? (ignoring ajax requests)
if ((empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest')
&& ($regenerateTime = $this->sessionTimeToUpdate) > 0
) {
if (! isset($_SESSION['__ci_last_regenerate'])) {
$_SESSION['__ci_last_regenerate'] = time();
} elseif ($_SESSION['__ci_last_regenerate'] < (time() - $regenerateTime)) {
$this->regenerate((bool) $this->sessionRegenerateDestroy);
}
}
// Another work-around ... PHP doesn't seem to send the session cookie
// unless it is being currently created or regenerated
elseif (isset($_COOKIE[$this->sessionCookieName]) && $_COOKIE[$this->sessionCookieName] === session_id()) {
$this->setCookie();
}

@kenjis
Copy link
Member Author

kenjis commented Jun 21, 2022

setCookie() updates the cookie expiration time.

If a site uses a lot of Ajax requests, does it updating cookies so that session cookies don't expire?

@kenjis
Copy link
Member Author

kenjis commented Jun 21, 2022

@skuadron45 I sent a PR #6167
Please try if you can.

@skuadron45
Copy link

i already testing this commit, and it work, you are awesome @kenjis

With ajax on browser: Set Cookie only once.

gambar

With curl on terminal:
gambar

As you can see, Set Cookie still sent twice, but for the last order was new session and like just before v 4.2.0

The question is, is this normal Set Cookie sent twice if we request with CURL ?

I just wanna say, "Thanks kenjis for resolve this bug"

@kenjis
Copy link
Member Author

kenjis commented Jun 21, 2022

As you can see, Set Cookie still sent twice, but for the last order was new session and like just before v 4.2.0

I did not expect twice. It may be the bug of Apache and Session cookie of PHP.

I don't reproduce with spark serve.

$ curl -sv -H 'X-Requested-With: xmlhttprequest' http://localhost:8080/test
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> X-Requested-With: xmlhttprequest
> 
< HTTP/1.1 200 OK
< Host: localhost:8080
< Date: Tue, 21 Jun 2022 21:24:18 GMT
< Connection: close
< X-Powered-By: PHP/8.0.20
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Set-Cookie: ci_session=g3olhnaja8ph38c38h8h8qbvajlnfe8e; expires=Tue, 21-Jun-2022 23:24:18 GMT; Max-Age=7200; path=/; HttpOnly; SameSite=Lax
< Cache-control: no-store, max-age=0, no-cache
< Content-Type: text/html; charset=UTF-8
< Debugbar-Time: 1655846658.941136
< Debugbar-Link: http://localhost:8080/index.php?debugbar_time=1655846658.941136
< 
* Closing connection 0
{"old":"b1n05t5aocklspaandrgg71c7m8snmgi","old_data":[],"new":"g3olhnaja8ph38c38h8h8qbvajlnfe8e","new_data":{"__ci_last_regenerate":1655846658}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Verified issues on the current code behavior or pull requests that will fix them
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants