📜 ⬆️ ⬇️

PHP: Storing sessions in protected cookies

At some stage in the development of a web project, one of the following situations occurs:


Traditionally, in such cases, Redis, Memcached, or some other external storage are used to store user sessions. As a result, the burden of operating the database arises, which in this case should not be a single point of failure or a bottleneck in the system.

However, there is an alternative to this approach. It is possible to safely and reliably store session data in a browser cookie at the user’s own, if you verify the session data with a cryptographic signature. If, in addition to this, the data is also encrypted, then the contents of the session will not be available to the user. The main advantage of this storage method is that it does not require a centralized database for sessions, with all the advantages in terms of reliability, speed and scaling resulting from it.
')

Mechanism description


This idea is not new and is implemented in a variety of frameworks and libraries for various programming languages. Here are a couple of examples:


It is worth noting that in Ruby on Rails they make a big bet on the performance of this mechanism in comparison with all other session storage methods and use it by default.

Most of the existing implementations work as follows: write a string containing the session expiration time, session data and the HMAC signature of the expiration time and data in some cookie. When a client requests a cookie, it is read by the corresponding handler, then the signature is checked and the current time is compared with the session expiration time. If everything matches, the handler returns the session data to the application.

However, cookies are not encrypted in common implementations of this mechanism.

Comparison with the classical approach


As a result, the storage of sessions in cookies has the following advantages :


There are also disadvantages , but without them:


Implementations for PHP


When I tried to find something similar for PHP, I was surprised to find that there is not a single library that meets the minimum requirements:


In addition, I think it is not superfluous:


The implementations I reviewed are:
RepositoryComment
github.com/Coercive/CookieIn fact, not a library for working with sessions at all. Puts an encrypted cookie without signing it.
github.com/stevencorona/SessionHandlerCookieClosest to the requirements, but still has significant drawbacks:
  • Potentially vulnerable to time attacks due to direct comparison of hash with sample
  • No encryption
  • No tests
  • Poor packaging of cookies
  • The expiration time of the cookie is not stored with the value and is not covered by the signature. It means. that the client, once received the data in the session, can reproduce them endlessly.
  • Small bugs: read () after write () within one script execution shows not what is written, etc.

github.com/mapkyca/Encrypted-Client-Side-Sessions

I also watched the implementation of storing sessions in cookies in the Slim 2.x framework, but there is no signature or encryption. What the authors immediately warned.

Why is signature verification and encryption important instead of signature insufficient? Firstly, there is a noticeable probability that a cookie with garbage will be decoded in some session, especially the recording of the session is short. Secondly, the line with the session is subjected to deserialization, and the input from the deserializer cannot be submitted from untrusted sources.

After all the searches, I decided to implement such a library on my own.

Own implementation


Packagist: packagist.org/packages/snawoot/php-storageless-sessions
Github: github.com/Snawoot/php-storageless-sessions
Installing from composer: composer require snawoot/php-storageless-sessions

Key features:


A few words about the choice of encryption mode. When using block encryption modes (ECB, CBC), the length of the ciphertext increases slightly. This is due to the fact that the length of the original message must be a multiple of the block size. Due to mandatory padding, the length increment is from one byte to the size of the cipher block. That is, for AES - from 1 to 16 bytes. When using streaming encryption modes (OFB, CFB, CTR, ...), the original message is not passed through the block cipher, instead the block cipher is used to form the gamma sequence, and then the length of the ciphertext exactly matches the length of the original message, which is better suited for the described tasks.

Examples of using


A small script illustrating how to work with this handler:

 <?php require_once("vendor/autoload.php"); header('Content-Type: text/plain'); $secret = '********************'; $handler = new VladislavYarmak\StoragelessSession\CryptoCookieSessionHandler($secret); session_set_save_handler($handler, true); session_start(); if ($_GET) { foreach ($_GET as $key => $value) $_SESSION[$key] = $value; echo "Updated session:"; } else echo "Current session data:\n"; var_dump($_SESSION); 

You can watch his work by setting different session values ​​in the request line at: https://vm-0.com/sess.php .

An example of symfony integration:

 framework: session: handler_id: session.handler.cookie services: session.handler.cookie: class: VladislavYarmak\StoragelessSession\CryptoCookieSessionHandler public: true arguments: ['reallylongsecretplease'] 


As a real demo, I connected this session handler to the first web application that came to mind that uses sessions. It turned out they DokuWiki: wiki.vm-0.com . The site has a registration and login, and the work of the sessions can be observed in cookies.

Thank you for your attention and I hope that this article will help the development of your projects.

Source: https://habr.com/ru/post/325452/


All Articles