Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Native session handler
  • Hello, I'm having a big question concerning sessions handling. PHP does a really awesome job to handle session natively. They are configured on the server (php.ini) and not in the app. So if we have several websites on 1 server, we only need to configure the server for the changes to be applied on all the websites. I didn't see anything in Fuel to use the native session handling, which a few more options than any implementation from Fuel. Like session.cookie_secure, session.cache_limiter, session.serialize_handler (can be set to wddx), session.url_rewriter.tags, session.hash_function and since php 5.4 all those awesome brand new session.upload_progress.* directives. Basically if I use the Fuel mechanism to handle sessions, I can't benefits from any of this. If I understand well, it's not the philosophy to provide a driver which has more functionality than the others, so maybe it's not a good idea to have this one. Should I just skip using the Session class and use plain old $_SESSION vars?
  • From a security point of view, I strongly disagree with you. PHP does an awesome job at providing you with an insecure, and potentionally very insecure session management system. It is the main reason why FuelPHP does not use it. We'll see what PHP 5.4 brings to the table, and perhaps reconsider our point of view and provide a native driver. Some of the items you name are around since PHP4. And haven't introduced any added security. If we decide to add a driver, the interface will still be the same, FuelPHP will not start using global PHP vars. But I don't see that happening, you will have to put quite a lot of effort in securing the server side of PHP sessions, and there is no way to really secure the client side of it. As long as a lot of users are dependent on the (non-existing) efforts of low-cost hosting companies, we will not provide an feature that is not secure and potentionally dangerous. Having said that, nobody's stopping you from writing your own class that uses native sessions. The security of your applications is your responsibility, and yours alone.
  • I'm also interested to see what PHP 5.4 has to give, the upload_progress feature especially could be a really good reason to use (part of?) it... I totally agree with you that the default configuration from PHP can be insecure. I understand the Session class from Fuel has a a better default configuration to handle security, by using a few possible additions like:
    - ua check (on by default)
    - ip check
    - session id rotation But that's nothing the native implementation could not do if it were a Fuel Session driver. Absolutely all session directives are configurable using ini_set(), apart from use_trans_sid which can be voided by use_only_cookies. So what would be less secure in a good configured "native session" driver compared to file driver provided?
    Besides, I can see one issue in the handling from Fuel which can lead to loss of data compared to the native implementation.
    You don't keep the lock until the session is closed. So we can open 2 sessions in parallel (ajax way), do different things in both and one of them will loose the data it wanted to save.
    We rely on this in our actual CMS and we use session_write_close() to release the session (and the execution flow) as soon as we can. This is not erratic behavior, I really think it's a feature we should be able to rely on.
  • The only part of native sessions that could be usable is the backend, which doesn't have any advantage over the current file driver. FuelPHP is not going to use PHP native sessions cookie management. It is insecure. Period. FuelPHP is also not going to use superglobals, so no $_SESSION. Leaving a driver that upon write() will copy the contents of the session storage to $_SESSION and does a session_write_close(), and does the reverse upon starting the session. I don't see the added value. As for the server side of native sessions, yes, you can configure it to be secure (enough). If you own your own servers, and know exactly what you are doing. Most developers however don't, or write applications for clients and have no influence on the setup of their servers. Since there is a good file-based session storage driver available, I don't see the reason to include a driver that uses PHP's native session backend. And as for concurrency, every session solution, including native sessions, has the same problem. Locking is no solution, it either provides ajax calls with a read-only session (which is not good when it's a POST) or with no access at all (which defaults the purpose of ajax). It is not an ajax specific issue, you have the same if you have multiple windows open to the same application that you use concurrently. In FuelPHP, You can only have a concurrency issue if you have multiple parallel ajax calls, on of with runs longer than the configured session id rotation time. If you configure that properly, there is no issue. The mechanism has been tested extensively, over a 24 hour period with continuously 10 concurrent requests of random duration. The issue can occur if you have a long running request, and within that request, you have a shorter one that rotates the session id. That request will update the session cookie with the new id. As soon as the long running is finished, it wants to update it's session but can no longer find the session data, since the id was rotated without that request knowing about it. Standard session solutions will then assume the session does not exist, start a new one, and send the session id of that new session back to the browser. This will break the application, as all session state for all windows and ajax requests is now gone. FuelPHP's session class has a mechanism to detect this situation, and pick up the new session id instead of creating a new session. It can't deal with a double rotation, but that can't happen if no request runs longer than the session rotation time. So if you're worried about session loss, you have one extra reason to use FuelPHP's session management over native sessions.
  • Then let me explain more clearly to you what I mean with "data loss", I'm not sure we understood each other. Because I just ran this little test , and it happens as I though it would:
    <?php
    
    namespace Test;
    
    class Controller_Session extends Controller
    {
      public function action_test_1()
      {
        \Session::set('test1', 'foo');
        sleep(3);
        return 'test 1';
      }
     
     public function action_test_2()
     &#123;
      \Session::set('test2', 'foo');
      sleep(3);
      return 'test 2';
     }
     
     public function action_read()
      {
        \Debug::dump(\Session::get());
        return '';
      }
     
      public function action_destroy()
      {
        \Session::destroy();
        return 'destroyed';
      }
    }
    

    I opened test/session/action_1 and test/session/action_2 in the same time (< 3 s interval). Then I read the session with test/session/read and surprise: the data from action_1 does not appear. Native session doesn't have this problem... It would have taken 6 seconds to execute both requests, but it would end up with the 2 values in the array. Which is what I want, of course. That's what I'm talking about with "data loss". In my point of view, the session data from action_1 has been lost. It has nothing to do with the session file not being found or something like that (which is what you may have understand. On a (not so) unrelated thing, I would like to know what's the benefit of storing the user agent and the ip adress (+created and updated) client-side. Wouldn't storing it server side achieve the same security with less HTTP overhead? (Considering the most common case, in which 99.9% of the time it's valid so we don't read the session data for nothing).
    I can see the encrypted cookie with no data is at least 0.5 ko which alone is not quite much, but for a standard page with some images, CSS and javascript, the multiplication increases this figure quite fast. For example with 20 resources, that's 10 ko of unnecessary data.
  • That's not data loss, that is not understanding how things work. FuelPHP's session library has been designed so that it reads the data when the session starts, and writes it when it ends. This is for performance reasons, write-on-set is a very expensive operation, especially when you're using a file or database driven backend. If you're interested in write-on-set functionality (it was present in an early version, but removed), just add a feature request: http://github.com/fuel/core/issues. The reason FuelPHP builds an encrypted session cookie that contains more then just the session id has to do with session hijacking. Which is what makes native sessions insecure. If you just have a cookie with a session id, I can steal it, and take over your session. Stealing cookies is very simple. The same danger exists with "remember me" cookies, which basically provide an auto-login without giving credentials. Very dangerous if not implemented securely. By storing the extra information in the cookie, the server can decrypt it, and compare the information in it with what it knows about the client. This way a stolen cookie is useless unless the person using it has the same IP address, and uses exactly the same browser. It is encrypted to prevent manipulation of the cookie, for example by swapping the IP address with your own IP. As always, security has it's downsides. But we feel you should never use this as an excuse to be slack when it comes to implementing security. As to overhead, it is common practice (for this particular reason) to store assets on a separate cookie-free domain. It also allows you to use more granulair caching settings, it's usually fine to cache assets for a long(er) time.
  • I do understand how it works. It's precisely why I'm asking such questions. It's just the behavior from Fuel Session is very different from native session which I'm familiar with. And by applying the same logic as native sessions to Fuel sessions I can end up to data missing.
    Write-on-set is not the solution for me, the performance hit would be too big. I'd prefer to lock the whole execution flow like native PHP session would do.
    As for the extra information I think either you didn't read (carefully) what I wrote or I really have issues explaining what I want. Here is a more precise / longer version:
    If the extra information to enforce the session validity was stored server-side (in the same place as the data is) instead of client-side, the security could be enforced in the same manner. Imagine my cookie contains only my session_id. If you steal it and use it instead of me, here is whay happens on the server:
    - my session is read (based on the id): both my session data and the extra informations (ip address and user agent) are retrieved
    - the server compares the extra information with what it knows about the client... and reject it because it doesn't match with my ip address and/or browser So the cookie you stole to me is useless, because in the end, to use my session, you still need to have the same IP and browser I have. Even if the cookie doesn't contain this piece of information. In my sense it's even more secure because there is no way to manipulate the data client side as it doesn't even exists. What matters is that we have this extra information, not where it is stored (as long as we can associate it with the appropriate session id).
    And if you followed up to here, I hope you will agree that the cookie is not really the problem for session security... and that native session can achieve the same level of security than Fuel does?
  • No more thoughts on this ?
  • Yes, lots. write-on-set is usesless for cookie based sessions. Everytime you modify a session variable a new cookie is added to the header, which if you're unlucky makes your header bigger then the page itself. Not to mention the fact that some browsers have issues with large headers. Besides that, as long as the page hasn't been send to the browser, ajax requests don't benefit from it's updates. write-on-set is possible for database backed sessions, but with a substantial I/O penalty due to the fact that every modification means running an update query. For file based backends (such as native sessions) to overhead is less, but still substantial. Only with a memory based backend like APC or memcached you don't suffer from the write-on-set mechanism. If you're interested in getting that feature back, add a feature request at http://github.com/fuel/core/issues. Storing information server side is off course possible, but than means no more generic drivers, as the cookie based session doesn't have any server side storage. It also means additional I/O, because you will have to access the session data before detecting a violation. This is something I'll have to think about. Besides all that, the security concerns of the way PHP sessions are handled server side (by default) on most servers still means I'm not in favour of creating a driver for it.
  • Once again, I'm not interested in a write-on-set functionality, as this doesn't solve my concurrency problem. I'd better like a lock mechanism, but this is not possible / optimal with every driver. When I said storing the data "on the server", I really meant using the driver backend storage. When using the cookie driver, information will still be stored in the cookie, obviously. I didn't want to jeopardize genericity with that. As I said before the additional I/O due to accessing the data before detecting the violation is insignificant, because 99.9% of the time, there is no violation. This is not the problem IMHO. I perfectly understand the reason you don't want a driver for native session and I'm fine with it. The discussion was now on ways to improve the existing system. A bottleneck I can see is the cookie encryption, which is quite costly. It needs to load the library (several files), the crypt configuration file and run expensive maths on the cookie string to perform the decoding / encoding (which is a lot of CPU cycles).
    If security data (IP + user agent) was to be stored in the backend, then less data would need to be encoded / decoded, reducing the computation time and improving performance.
    But that's still costly, and I think an option the disable the encryption would be useful for people in need of high performances.
  • I as said, I don't have an issue with reviewing the session drivers for 1.2.
    Please create an issue for this so we can put it on the roadmap. As for the write-on-set, it is something I have to think about, since I'm not happy with locking for several reasons. First, it is only technically possible for file based sessions. For all other backends, a locking mechanism must be designed which can be quite complicated. Secondly, most people need session access in their ajax calls, but if properly designed, you don't need write access. If concurrent write access is required (I can imagine that being a requirement), we have to redesign the session mechanism to make this work.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion