[RFC][Discussion] Precise session data management

php.internals

Yasuo Ohgaki

10 years ago
Hi all, Since the vote for https://wiki.php.net/rfc/precise_session_management is declined 15 vs 11. https://wiki.php.net/rfc/precise_session_management#vote We have to come up with other solutions for - Session loss by race conditions - Method to make session abuse harder I'm open to implement better solution than proposed RFC. These issues are serious issues that cannot be ignored. Looking forward alternative implementation ideas! Thank you.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi all, On Thu, Mar 24, 2016 at 11:34 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> We have to come up with other solutions for > > - Session loss by race conditions > - Method to make session abuse harder
I'll explain how attacker can steal PHP sessions forever with current session module. There are multiple serious issues in current session management. I suppose this makes difficult to understand what wrong with current session. Any stolen session is not acceptable, but I'll focus cases only that allows session abuse forever to make discussion simpler. ** Exploit 1 ** Attack adoptive session management Internet RFC does not define cookie precedence for multiple outstanding cookies. Therefore, when multiple cookies for "httponly", "secure", web site domain names, web app path are set, it's up to browser implementation which cookie is sent to browser. Attacker can set undeletable cookie by using this behavior. i.e. Simple Set-cookie cannot delete nor update session ID cookie, but attacker's session ID stay as outstanding session ID cookie forever. If you experiment how browsers behave, you'll be surprised how easy to set undeletable cookie by single XSS. You'll be surprised how some browsers manage cookie by insane way also. Requirement "session.use_strict_mode=0". This is the default Note "session.use_strict_mode=1" can mitigate issue a little, but remained risk is not acceptable. Attacker may use next attack method explained to keep active session (to avoid GC). "session.use_strict_mode=1" creates client side race condition also. This results in lost sessions on occasion. ** Exploit 2 ** Attack static session ID Stealing active session is easy especially when physical access to device is possible. It's just a matter of displaying cookies for a website and take picture, then abuse. When https is not used, stealing active session ID is trivial by ARP spoofing, evil twins, etc. Even if https is used, setting up https stripping proxy is trivial and HSTS is not used widely. Attackers can keep active session forever by accessing stolen session periodically before GC. Requirement Application that does not call session_regenerate_id() after login and has no expiration period for active sessions. In addition, PHP does not have any attack detection for these attacks while precise session management proposal does. Inclusion, if I were attacker, I would say attacking PHP session is easy and safe (undetectable) by poor session management. Let's discuss how we are going to address these issues and fix them. My opinion is "PHP's session manager must be safe against these attacks by default/out of the box. Users should not have to write code and manage basic session status". Those who were vote against the proposal, please let me know which part of my RFC is not good enough at least, better proposal is appreciated of course. Thank you.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Joe Watkins

10 years ago
Morning Yasuo, First, thanks for all the effort ... You already know that, a refusal to merge a patch doesn't mean you wasted your time, it should serve to refocus your research. So, I thought I'd say some stuff, to aid with that ... The first thing I would do is break down the problem into smaller, much smaller, RFC's: We know there are many inconsistencies in the language, we could write a huge long list, and do a bumper RFC to solve them all at once. But would that be a good idea !? As already mentioned it's much easier to consider each problem on it's own, and the solution for that problem on it's own, than it is to consider what we are going to do about this huge mess. Try to remember that while you have had your head buried in this stuff for a long time, the rest of us likely haven't. I don't really like to talk about security, it's not a thing I feel qualified to talk about ... but, there is inconsistency in saying "we should have a secure by default session module", and then introducing ini settings that can vary the effectiveness of the solution, based on guesses about the length, and speed at which elevators travel ... Having another setting which seems to be 18 times longer than the recommended value for "low security applications" is also extremely odd to me ... That you can't find sensible defaults for these values, says to me that these problems don't have solutions in our domain; Application security is a problem that can only be solved by the programmer using PHP. We should provide the tools, we should not lie about the validity of a session because of faults in our design, every layer we provide should be consistent, but the problem still belongs to the programmer using PHP. Cheers Joe On Thu, Mar 24, 2016 at 4:18 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:

Yasuo Ohgaki

10 years ago
Hi Joe, On Thu, Mar 24, 2016 at 4:22 PM, Joe Watkins <pthreads@pthreads.org> wrote:
> > First, thanks for all the effort ... You already know that, a refusal to > merge a patch doesn't mean you wasted your time, it should serve to refocus > your research. > > So, I thought I'd say some stuff, to aid with that ... > > The first thing I would do is break down the problem into smaller, much > smaller, RFC's: We know there are many inconsistencies in the language, we > could write a huge long list, and do a bumper RFC to solve them all at once. > But would that be a good idea !?
Splitting patch is not a problem. Some changes are interrelated, but many could be applied individually.
> > As already mentioned it's much easier to consider each problem on it's > own, and the solution for that problem on it's own, than it is to consider > what we are going to do about this huge mess. Try to remember that while you > have had your head buried in this stuff for a long time, the rest of us > likely haven't. > > I don't really like to talk about security, it's not a thing I feel > qualified to talk about ... but, there is inconsistency in saying "we should > have a secure by default session module", and then introducing ini settings > that can vary the effectiveness of the solution, based on guesses about the > length, and speed at which elevators travel ... > > Having another setting which seems to be 18 times longer than the > recommended value for "low security applications" is also extremely odd to > me ... > > That you can't find sensible defaults for these values, says to me that > these problems don't have solutions in our domain; Application security is a > problem that can only be solved by the programmer using PHP. > > We should provide the tools, we should not lie about the validity of a > session because of faults in our design, every layer we provide should be > consistent, but the problem still belongs to the programmer using PHP.
I agree. It's like using TCP or UDP. I don't mind much either way, but I prefer TCP like behavior for session manager because session manager jobs is keeping reliable session. Current PHP session is UDP, users are responsible use it correctly. If we keep UDP way, I think we should remove session_regenerate_id(TURE) at least. i.e. Remove deletion option from session_regenerate_id() because it doesn't work and bad way to manage session ID. I'll write PHP code for those who are care about session reliability and security. Following code is minimum code. I wrote this code directly, so take this as pseudo code. I might be missing something as I do not verify this code, but it should be good enough to know what users must do. Using UDP like TCP is not too difficult, but not too simple also. Session management is the same. <?php ini_set('session.use_strict_mode', 1); session_start(); if (isset($_SESSION['deleted']) && $_SESSION['deleted'] < time() - 600) { trigger_error('Possible attack detected'); session_unset(); session_destroy(); session_start(); session_regenerate_id(); } // if you cannot loose session on occasion, execute following if block also. if (isset($_SESSION['deleted']) && $_SESSION['deleted'] < time() - 60 && isset($_SESSION['new_id'])) { $new_id = $_SESSION['new_id']; unset($_SESSION['new_id']); session_commit(); session_id($new_id); session_start(); } if (!isset($_SESSION['update'] || (!isset($_SESSION['deleted']) && $_SESSION['updated'] < time() - 180)) { // Should not update updated timestamp always $_SESSION['updated'] = time(); } if (empty($_SESSION['regenerated']) { // New session $_SESSION['regenerated'] = time(); } if ($_SESSION['regenerated'] < time() - 1800) { // This code does not keep older session IDs. If you need them, save them here also. $_SESSION['deleted'] = time(); session_commit(); // Older PHP must close session to write session data. PHP 7.0 and up does not need this. session_start(); // Since session is closed, session has to be started. PHP 7.0 and up does not need this. $old_id = session_id(); session_regenerate_id(); $new_id = session_id(); $_SESSION['regenerated'] = time(); unset($_SESSION['deleted']); // if you cannot loose session on occasion, execute following code also. session_commit(); session_id($old_session); session_start(); $_SESSION['new_id'] = $new_id; session_commit(); session_id($new_id); session_start(); } ?> This is not equal to what the proposed patch does. This is the least requirement for reliable session management. It's much less efficient in user script. It's cost of user space implementation. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Chris Riley

10 years ago
On 24 March 2016 at 02:34, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> Hi all, > > Since the vote for > https://wiki.php.net/rfc/precise_session_management > is declined 15 vs 11. > https://wiki.php.net/rfc/precise_session_management#vote > > We have to come up with other solutions for > > - Session loss by race conditions > - Method to make session abuse harder > > I'm open to implement better solution than proposed RFC. > > These issues are serious issues that cannot be ignored. > Looking forward alternative implementation ideas! > > Thank you. > > -- > Yasuo Ohgaki > yohgaki@ohgaki.net > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
I'm disappointed this RFC failed as improving session security should be a high priority. I'd propose that we focus on items which will improve session security overall. This jumped out at me to start with: "This RFC also includes minor security improvements like httponly cookie, better hash function." Perhaps a first RFC for improving session security can start with those items: Set the session cookie to be httponly (or provide an ini setting to do so, defaulting to on) instead of using a better hash function for the session id, why not generate it from random_bytes()? Then the id is crypto secure. I'd then consider a second RFC setting out the extra internal data that would be required to kill off old sessions correctly. That would require to keys under ['__PHP__SESSION__'] (could the key name be an ini setting to preserve BC?) 'destroyed' and 'expires', the latter would be a bool flag stating if the session had been explicitly destroyed. (A destroyed session could no longer be used, could throw an exception or just have no data in it) the expires key would be used in a similar manner, being set to Time+cookie expiry time on each read/write to the session. (again an expired session would not be accessible and would function like a destroyed one) The combination of the two would resolve most of the security issues and establish the __PHP__SESSION__ key which could later be used to handle the race condition issue.

Scott Arciszewski

10 years ago
On Thu, Mar 24, 2016 at 9:55 AM, Chris Riley <t.carnage@gmail.com> wrote:
> On 24 March 2016 at 02:34, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote: > > > Hi all, > > > > Since the vote for > > https://wiki.php.net/rfc/precise_session_management > > is declined 15 vs 11. > > https://wiki.php.net/rfc/precise_session_management#vote > > > > We have to come up with other solutions for > > > > - Session loss by race conditions > > - Method to make session abuse harder > > > > I'm open to implement better solution than proposed RFC. > > > > These issues are serious issues that cannot be ignored. > > Looking forward alternative implementation ideas! > > > > Thank you. > > > > -- > > Yasuo Ohgaki > > yohgaki@ohgaki.net > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > > > > > I'm disappointed this RFC failed as improving session security should be a > high priority. I'd propose that we focus on items which will improve > session security overall. This jumped out at me to start with: "This RFC > also > includes minor security improvements like httponly cookie, better hash > function." > > Perhaps a first RFC for improving session security can start with those > items: Set the session cookie to be httponly (or provide an ini setting to > do so, defaulting to on) instead of using a better hash function for the > session id, why not generate it from random_bytes()? Then the id is crypto > secure. > > I'd then consider a second RFC setting out the extra internal data that > would be required to kill off old sessions correctly. That would require to > keys under ['__PHP__SESSION__'] (could the key name be an ini setting to > preserve BC?) 'destroyed' and 'expires', the latter would be a bool flag > stating if the session had been explicitly destroyed. (A destroyed session > could no longer be used, could throw an exception or just have no data in > it) the expires key would be used in a similar manner, being set to > Time+cookie expiry time on each read/write to the session. (again an > expired session would not be accessible and would function like a destroyed > one) > > The combination of the two would resolve most of the security issues and > establish the __PHP__SESSION__ key which could later be used to handle the > race condition issue. >
Could we also add HTTPS detection and enable the secure flag by default when a session is established on an HTTPS endpoint? Scott Arciszewski Chief Development Officer Paragon Initiative Enterprises <https://paragonie.com/> ​

Chris Riley

10 years ago
On 24 March 2016 at 14:43, Scott Arciszewski <scott@paragonie.com> wrote:
> On Thu, Mar 24, 2016 at 9:55 AM, Chris Riley <t.carnage@gmail.com> wrote: > >> On 24 March 2016 at 02:34, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote: >> >> > Hi all, >> > >> > Since the vote for >> > https://wiki.php.net/rfc/precise_session_management >> > is declined 15 vs 11. >> > https://wiki.php.net/rfc/precise_session_management#vote >> > >> > We have to come up with other solutions for >> > >> > - Session loss by race conditions >> > - Method to make session abuse harder >> > >> > I'm open to implement better solution than proposed RFC. >> > >> > These issues are serious issues that cannot be ignored. >> > Looking forward alternative implementation ideas! >> > >> > Thank you. >> > >> > -- >> > Yasuo Ohgaki >> > yohgaki@ohgaki.net >> > >> > -- >> > PHP Internals - PHP Runtime Development Mailing List >> > To unsubscribe, visit: http://www.php.net/unsub.php >> > >> > >> I'm disappointed this RFC failed as improving session security should be a >> high priority. I'd propose that we focus on items which will improve >> session security overall. This jumped out at me to start with: "This RFC >> also >> includes minor security improvements like httponly cookie, better hash >> function." >> >> Perhaps a first RFC for improving session security can start with those >> items: Set the session cookie to be httponly (or provide an ini setting to >> do so, defaulting to on) instead of using a better hash function for the >> session id, why not generate it from random_bytes()? Then the id is crypto >> secure. >> >> I'd then consider a second RFC setting out the extra internal data that >> would be required to kill off old sessions correctly. That would require >> to >> keys under ['__PHP__SESSION__'] (could the key name be an ini setting to >> preserve BC?) 'destroyed' and 'expires', the latter would be a bool flag >> stating if the session had been explicitly destroyed. (A destroyed session >> could no longer be used, could throw an exception or just have no data in >> it) the expires key would be used in a similar manner, being set to >> Time+cookie expiry time on each read/write to the session. (again an >> expired session would not be accessible and would function like a >> destroyed >> one) >> >> The combination of the two would resolve most of the security issues and >> establish the __PHP__SESSION__ key which could later be used to handle the >> race condition issue. >> > > Could we also add HTTPS detection and enable the secure flag by default > when a session is established on an HTTPS endpoint? > > Scott Arciszewski > Chief Development Officer > Paragon Initiative Enterprises <https://paragonie.com/> > ​ > >
I had considered this suggestion myself, but I wasn't sure if it would be easy to implement. It could also cause some very strange (to a novice developer) behaviour which would be hard to debug (Think sites which have part http part https, session behaviour would be dependant on the entry page the user hits) I'd support this, but it should probably be opt-in to start with (alternatively we could come up with a different way to allow the developer to specify sessions being ssl only)

Colin O'Dell

10 years ago
I'm +1 for splitting it into smaller chunks. I didn't fully comprehend the impact of some aspects of the RFC and therefore didn't feel it was appropriate for me to cast a vote either way. However, if the different pieces were broken out into smaller, more-focused RFCs I would likely vote for most of them. Regards, Colin

Stas Malyshev

10 years ago
Hi!
>> Could we also add HTTPS detection and enable the secure flag by default >> when a session is established on an HTTPS endpoint?
You can not see if your connection would be HTTPS or not - connection can be terminated on frontend services (like nginx or varnish) that handle https and the pass the actual work to backend like fpm or apache or whatever it is. In this situation, you may have no information about if the connection to the client is HTTPS or not. And in general, AFAIK there is no standard protocol to establishing this kind of info. There are all kinds of ways people do it, but each of them is peculiar for specific setup. I also think it is a mistake to have default behavior controlled by external factors beyond server admin's control. Server behavior should be predictable. The admin should set it up properly, if the admin is not knowledgeable enough to set it up, I don't think we can improve it by introducing variable defaults into the mix.
-- Stas Malyshev smalyshev@gmail.com

Chris Riley

10 years ago
You are right, perhaps this should be controlled simply by an ini flag: session https only. On Mon, 28 Mar 2016, 01:09 Stanislav Malyshev, <smalyshev@gmail.com> wrote:

Yasuo Ohgaki

10 years ago
Hi all, On Mon, Mar 28, 2016 at 9:23 PM, Chris Riley <t.carnage@gmail.com> wrote:
> You are right, perhaps this should be controlled simply by an ini flag: > session https only. > > > On Mon, 28 Mar 2016, 01:09 Stanislav Malyshev, <smalyshev@gmail.com> wrote: >> >> Hi! >> >> >> Could we also add HTTPS detection and enable the secure flag by default >> >> when a session is established on an HTTPS endpoint? >> >> You can not see if your connection would be HTTPS or not - connection >> can be terminated on frontend services (like nginx or varnish) that >> handle https and the pass the actual work to backend like fpm or apache >> or whatever it is. In this situation, you may have no information about >> if the connection to the client is HTTPS or not. >> >> And in general, AFAIK there is no standard protocol to establishing this >> kind of info. There are all kinds of ways people do it, but each of them >> is peculiar for specific setup. >> >> I also think it is a mistake to have default behavior controlled by >> external factors beyond server admin's control. Server behavior should >> be predictable. The admin should set it up properly, if the admin is not >> knowledgeable enough to set it up, I don't think we can improve it by >> introducing variable defaults into the mix.
It can be made half-automatic by specifying and detecting HTTPS connection flag. I think half-automatic will be mostly the same as current httponly INI setting. It could be confusing for sites that support both HTTP and HTTPS, too. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi, On Thu, Mar 24, 2016 at 11:34 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> Since the vote for > https://wiki.php.net/rfc/precise_session_management > is declined 15 vs 11. > https://wiki.php.net/rfc/precise_session_management#vote > > We have to come up with other solutions for > > - Session loss by race conditions > - Method to make session abuse harder > > These issues are serious issues that cannot be ignored. > Looking forward alternative implementation ideas!
I would like to start reworking on this proposal. I need feedback the reason why vote against the RFC. Looking forward disclosure. Is splitting RFC up enough? Thanks.
-- Yasuo Ohgaki yohgaki@ohgaki.net