Potential race condition issue in CHttpSession::freeze()/unfreeze()
karelvasicek opened this issue · 10 comments
What steps will reproduce the problem?
- 2 parallel requests (
req1
andreq2
) - session opened not using
Yii::app()->session->open()
(we have mixed Yii1&Yii2 project and session is opened by Yii2 beforesession
Yii1 core component is initialized) cookieParams
set in config soCHttpSession::setCookieParams()
is called- call
Yii::app()->session->...
freeze()
called bysetCookieParams()
really freezes session as it is opened by Yii2 already- when session is frozen (closed, in fact) during processing
req1
, it can be opened byreq2
and sessions get mixed
(Theoretical; it's hard to reproduce the issue and even harder to debug) process:
req1 starts
req1 opens session
req1 loads value_stored_in_session 'A'
req2 starts
(req2 cannot open session, it's locked by req1 => waits)
req1 freezes (closes) session (stores 'A' to _frozenData)
req2 opens session
(req1 cannot unfreeze session, it's locked by req2 => waits)
req2 loads value_stored_in_session 'A'
req2 freezes (closes) session (stores 'A' to _frozenData)
req1 unfreezes session
(req2 cannot unfreeze session, it's locked by req1 => waits)
req1 has value_stored_in_session 'A' in _frozenData
req1 changes value_stored_in_session to 'B'
req1 closes session
req1 saves value_stored_in_session 'B' !!!! (correct, expected)
req2 unfreezes session
req2 has value_stored_in_session 'A' in _frozenData !!!!
req2 closes session
req2 saves 'A' !!!!
What is the expected result?
$_SESSION['value_stored_in_session']
containing value 'B'
after req1
is finished and this 'B'
value loaded from session by req2
.
What do you get instead?
Value 'A'
stored in session.
Additional info
Q | A |
---|---|
Yii version | 1.1.25 |
PHP version | 7.4.9 |
Operating system | Fedora |
@karelvasicek I'm not sure this scenario can really be fixed with framework code. Perhaps you should consider a different (session) storage solution?
@marcovtwout I don't think that different storage would make any difference, since the main problem here is that Yii stores session data in _frozenData
, which may be outdated when session is unfreezed.
I'm not sure this scenario can really be fixed with framework code.
This is indeed a very rare scenario, but IMO the system should not allow req2
to open the session when req1
is processed ( = when session is frozen by req1
), in general. flock()
ing might help?
Perhaps you should consider a different (session) storage solution?
We worked it around by initiating Yii1 session
component before session is open()
ed by Yii2 so freezing/unfreezing is not performed any more.
Would this scenario be reproducable in a Yii 2 project as well? As far as I can tell it uses the same mechanism with "freezing/unfreezing" and keeping session data in memory when changing cookie params.
Would this scenario be reproducable in a Yii 2 project as well?
Yes, it's reproducible. I added sleep(60)
to unfreeze()
to be able to (reliably) start req2
in between freeze()
and unfreeze()
of req1
and used following actions
public function actionReq1()
{
Yii::$app->session['var'] = 'A';
Yii::$app->session->setName('A');
return Yii::$app->session->id;
}
public function actionReq2()
{
Yii::$app->session['var'] = 'B';
Yii::$app->session->setName('B');
return Yii::$app->session->id;
}
Steps to reproduce:
- use
sleep(60)
inunfreeze()
- open
req1
- comment out
sleep(60)
inunfreeze()
- open
req2
req2
endscat sess_...
=>__flash|a:0:{}var|s:1:"B";
req1
endscat sess_...
=>__flash|a:0:{}var|s:1:"A";
@karelvasicek Could you post this issue in the yii2 issue tracker as well? Development is more active there, and whatever fix they choose could then potentially be applied here.
Could you post this issue in the yii2 issue tracker as well?
yiisoft/yii2#19599 is created.
Is there a reason why one would call CHttpSession::setCookieParams() (or session_set_cookie_params()) after a session is started? Seems like this could be resolved by doing that before session_start() is called
I suggest to pursue this issue first in yiisoft/yii2#19599. As yii1 is in maintainance mode there is a better chance the issue will be fixed in yii2 first, and perhaps later we can backport it.
For now I'm marking this as a wontfix, unless yiisoft/yii2#19599 leads to a solution which can be backported.