Skip to end of metadata
Go to start of metadata

Zend Framework: Zend_Session_SaveHandler_Cookies Component Proposal

Proposed Component Name Zend_Session_SaveHandler_Cookies
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Session_SaveHandler_Cookies
Proposers Romain Lalaut
Zend Liaison TBD
Revision 1.0 - 4 January 2009: Initial Draft and implementation.
1.1 - 4 February 2009: First revision. (wiki revision: 21)

Table of Contents

1. Overview

Zend_Session_SaveHandler_Cookies is a save handler which stores data into the cookies client.

Pros

  • Speed improvement : a little overhead for the CPU but no disk I/O,
  • Easier system administration : no garbage collector, no need to have a centralized repository for sessions data when you have a farm of servers.

Cons

  • Cannot send any data to the client before calling session_write_close(),
  • HTTP traffic overhead because the session data is sent for each request,
  • Because of cookies restrictions, the size of session data is limited (20 cookies per domain and 4096 bytes per cookie = 81,920 bytes).

Features

  • Splits the session data into multiple cookies to circumvent the storage limitation of 4096 bytes per cookie.
  • Using HMAC to check the integrity of the received data.
  • Can optionally encrypt the cookies using various algorithms (built-in xor, those in mcrypt extension).
  • Can optionally compress the data (deflate, gzip, bzip2)

Security considerations

  • Because the mcrypt extension isn't enabled by default in php, the default configuration uses a XOR cipher. This simple algorithm is vulnerable to a known-plaintext attack and although the encryption is not mandatory to assure the session integrity, it's recommended to use strong mcrypt's algorithms like rijndael-256 if the session data contains sensible informations.
  • You have to set at least one private secret key (the _dataKey_ option) but it's recommended to set the second too.
  • ... (see comments)

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will implement Zend_Session_SaveHandler_Interface.
  • This component will send cookies strictly complying with RFC 2109.
  • This component will ignore some Zend_Session configuration options which are irrelevant : gc_divisor, gc_maxlifetime, gc_probability, save_path, use_cookies, use_only_cookies.
  • This component will check the integrity of every input cookie with an HMAC.
  • This component will optionnally encrypt the content of the cookies using various algorithms (rot13, xor, those in mcrypt).
  • This component will optionnally compress the content of the cookies in various formats (gzip, bzip2, deflate).
  • This component require that session_write_close() is called before any output is sent to the client.

4. Dependencies on Other Framework Components

  • Zend_Session

5. Theory of Operation

When the open() method is called, the cookies sent by the client are parsed (decryption, decompression, HMAC check) and, if everything is ok, the data session is returned by the read() method.

When invoking the close() method, after that write() was called, the reverse operation is processed : HMAC generation, compression, encryption of the session data. Finally, one or more cookies are sent to the client.

Restrictions of the current implementation
The "remember me" feature is not implemented : the session will live until the user closes his browser.

6. Milestones / Tasks

  • Milestone 1: [DONE] Initial implementation.
  • Milestone 2: [DONE] Use some Zend_Session configuration options and Zend_Config in the constructor instead of a php array.
  • Milestone 3: Implements the "remember me" feature and the session expiration.
  • Milestone 4: Unit tests exist (ok), work (ok), and are checked into SVN.
  • Milestone 5: Initial documentation exists.

7. Class Index

  • Zend_Session_SaveHandler_Cookie

8. Use Cases

UC-01

A very basic usage : no encryption and no compression.

UC-02

A simple usage : XOR encryption, no compression

UC-03

A more complex usage :

  • HMAC : whirlpool (>= php-5.3), sha-1 (< php-5.3),
  • Encryption : rijndael-256 (cbc).
  • Compression : deflate

9. Class Skeletons

See the attachments to get the current implementation.

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Feb 01, 2010

    Hi Romain,

    In no specific order (just typing as I read the proposal).

    Can you expand the Overview with some details to explain why a Cookie store is useful, how it is secured against user manipulation, and post a set of highlights on its advantages and disadvantages. I'm willing to bet this is why you haven't seen comments yet, and the more information/details you provide the easier it will be to understand the proposal and pass comments.

    Same goes for Theory Of Operation.

    How will the component handle the banes of Cookies? The first is that Cookies have a size limit of 4K. For most session uses this is more than sufficient, but it's not mentioned anywhere. Also not mentioned is that the Cookie needs to be sent with all requests (another minor issue). On the application side, do Cookies introduce any other limits on what can or should be stored to the Session?

    In the context of the Cookie size restriction, can we avoid using base64 encoding? It's notorious for increasing the size of plain text data.

    On line 371, can we replace the direct HMAC comparison with a fixed time equation? Direct comparisons of hashes can leak information about the validity of an attempted HMAC guess, for example, a string comparison fails at the first unknown character meaning the closer a guessed HMAC is to the real one, the slower the comparison fails. An attacker theoretically could use this instead of a brute force attack to figure out the right hash to send with altered Cookies. I can provide a sample comparison function that's safer.

    If you have unit tests available, it would do no harm to attach those to the proposal also .

    Very minor - the code will need to be edited to conform to the framework's coding standard (mostly ensuring the use of paired braces). Also, where possible, refactor __construct() a little. It would be nice to bundle the encryption strategies closer and test before making their method calls (as opposed to making the call and letting it return null). These were barely worth mentioning - the code is fine otherwise.

    The main topic you will see going forward in comments is security/utility. The utility won't be a problem. I would recommend adding a dedicated security section to the Overview detailing the the vulnerabilities of Cookie stored sessions and how they are (or are not) addressed by your class. The class can't address all of them (e.g. what data is stored there), but many of them can be (HMAC, encryption, expire? on failed decryption/hmac, etc.). Mostly this is to inform the reader who probably won't be up to date on all the security implications of similar session stores.

    My main area of concern would be session replay (a possible attack) - how should expiration be handled without garbage collection?

    One last minor note is reserved for encryption - we should assume users won't meddle too much with mcrypt's defaults as presented, so it would be a good idea to default to a random generator most appropriate to the server. At present its set to RAND, but a quick file check would tell you if URANDOM was supported locally from /dev/urandom.

    Good luck!

    1. Feb 01, 2010

      Hey Romain,

      I second all of Padraic's suggestion and want to add that you avoid private and instead use protected. Often components will be extended by the developers using them and private makes it generally harder to do so.

      All in all, this is a great proposal – because it adds one of the features to ZF which I really like in Rails.

    2. Feb 04, 2010

      Can you expand the Overview with some details to explain why a Cookie store is useful, how it is secured against user manipulation, and post a set of highlights on its advantages and disadvantages. I'm willing to bet this is why you haven't seen comments yet, and the more information/details you provide the easier it will be to understand the proposal and pass comments.
      Same goes for Theory Of Operation.

      Ok. I completed theses parts.

      How will the component handle the banes of Cookies? The first is that Cookies have a size limit of 4K. For most session uses this is more than sufficient, but it's not mentioned anywhere. Also not mentioned is that the Cookie needs to be sent with all requests (another minor issue). On the application side, do Cookies introduce any other limits on what can or should be stored to the Session?

      As explained in the overview, the handler may use many cookies to store the session data. Therefore the limit related to cookies is higher.

      And yes, sending the cookies with all requests is an issue to be mentioned. But with the compression mechanism, we can keep cookies relatively small for most sessions uses.

      The most important issue with the current implementation is that it doesn't implement the "remember me" feature (the cookies will survive after the browser session) and more generally the session expiration. I have some ideas but they leads to send a different cookie for each request (to have the time of the previous request). Else we could only send this information when session data are modified. Besides, I was amazed to see that the default handler applies this logic with its garbage collector ( session.gc_maxlifetime : " Since PHP 4.2.3 it has used mtime (modified date) instead of atime. "). So I don't know... Suggestions are welcome !

      Otherwise I don't see any other restriction when using this handler.

      In the context of the Cookie size restriction, can we avoid using base64 encoding? It's notorious for increasing the size of plain text data.

       Yes it does. But since some parts or even all the cookies are binary (HMAC and the data when the encryption is used), we have to convert to ASCII. And it seems that the alternatives (uuencode, quoted-printable, hexa) are not more efficient in such cases. However perhaps it is better to let the developer choose.

       On line 371, can we replace the direct HMAC comparison with a fixed time equation? Direct comparisons of hashes can leak information about the validity of an attempted HMAC guess, for example, a string comparison fails at the first unknown character meaning the closer a guessed HMAC is to the real one, the slower the comparison fails. An attacker theoretically could use this instead of a brute force attack to figure out the right hash to send with altered Cookies. I can provide a sample comparison function that's safer.

       Ok. I don't know how to implement this but I added a random pause after a failed HMAC check. I don't know if it will be sufficient but I wonder how it's possible to gather such information since there is a high latency on the web ?

       If you have unit tests available, it would do no harm to attach those to the proposal also .

       I added some tests in the proposal attachment. They probably will need some work again.

       Very minor - the code will need to be edited to conform to the framework's coding standard (mostly ensuring the use of paired braces). Also, where possible, refactor __construct() a little. It would be nice to bundle the encryption strategies closer and test before making their method calls (as opposed to making the call and letting it return null). These were barely worth mentioning - the code is fine otherwise.

       I tried to follow theses advices. Perhaps I didn't see some parts...

       The main topic you will see going forward in comments is security/utility. The utility won't be a problem. I would recommend adding a dedicated security section to the Overview detailing the the vulnerabilities of Cookie stored sessions and how they are (or are not) addressed by your class. The class can't address all of them (e.g. what data is stored there), but many of them can be (HMAC, encryption, expire? on failed decryption/hmac, etc.). Mostly this is to inform the reader who probably won't be up to date on all the security implications of similar session stores.My main area of concern would be session replay (a possible attack) - how should expiration be handled without garbage collection?

       The only security flaw I could see is indeed the session replay and the need to manage the session expiration. Therefore this should be implemented.

       I also added a section on security considerations.

      One last minor note is reserved for encryption - we should assume users won't meddle too much with mcrypt's defaults as presented, so it would be a good idea to default to a random generator most appropriate to the server. At present its set to RAND, but a quick file check would tell you if URANDOM was supported locally from /dev/urandom.

       I don't understand : the default random source is setted to URANDOM and if the constant isn't defined it uses RAND (see the top of the file).

       Anyway, thanks for this constructive review.

      @Till : every private method is now protected

  2. Feb 07, 2011

    Archiving this proposal, feel free to recover it when you want to work on it again. For more details see this email.