Jump to content
Larry Ullman's Book Forums

Recommended Posts

Sure it can.

 

The thing about the DB route though is that you still have to use the session ID to get/set the session data in the DB. As such, you still need to security store the session files, as the session ID is essentially the key to all the sensitive data stored in the session, and you don't want anyone to get ahold of that.

 

As such, if you go the DB route, I think you should still do just about everything in my functions above, but in addition to that code, you also need to add all the necessary DB calls. In fact, this is why I didn't go the DB route with my functions. I personally feel like it adds a bunch of additional logic and inefficient DB calls that aren't warranted in most cases.

 

Like Larry says, two of the advantages of the DB route is having session data be available across servers and being able to run analytics on the sessions. However, unless you have either of those things in mind, I think the DB solution just adds extra code, which is less than ideal in my book.

 

With that said, one of my main goals with these functions is to make them solid and secure out of the box, but at the same time, make them simple enough that anyone can extend them as need be, including adding DB access for session data.

 

If you decide to hook my functions up to work with DB session data, please let us know what you find and so that anyone else that wants secure functions with a DB can reference your code.

Thank you.

Link to comment
Share on other sites

Jon,

 

Thanks for the hard work you have done with this!  The functions look great and include most of the best security practices for dealing with sessions.

 

I only had one question regarding the session_init() function.  Why did you leave out a property for specifying whether the connection is https?  You can then use that parameter to set whether the cookie is being sent over https or not like in the Treehouse Blog tutorial.  I have read that it is better to explicitly set all the cookie arguments when the session is created and to set HttpOnly to true as it's more secure.

 

What are your thoughts on this?

  • Upvote 1
Link to comment
Share on other sites

Yes, Matt, that is a good point.

I have added an additional parameter to the session_init function accordingly, which you can see in the revised function definition below.

 

Please note though that I defaulted the setting of secure cookies to false, as I feel like there are cases where a developer may want to use sessions over HTTP, and I didn't want to limit that possibility by default. (If I set secure cookies to true by default, then a developer using sessions with HTTP may run into all sorts of weird problems that are not easy to debug.)

 

In addition, like I mentioned before, I think it's a good idea to use HTTPS for everything anyway, so I think that the parameter would only be used for extreme edge cases anyway (but I could be wrong).

All the same, your point is a valid one, so I added the parameter accordingly.

 

<?php
  
  define('SITE_ROOT', 'C:\xampp\\');
  
  define('SESSION_SAVE_PATH', SITE_ROOT . 'd79252d7dea8e2812b4ebf29ffc603ed\\');
  
  define('SESSION_NAME', 'f7eac143c2e6c95e84a3e128e9ddcee6');
  
  // ...
  
  function session_init($regenerate_session_id = true, $secure_cookies_only = false, $timeout = 600) {
    
    session_save_path(SESSION_SAVE_PATH);
    
    session_name(SESSION_NAME);
    
    if ($secure_cookies_only) {
      
      ini_set('session.cookie_secure', '1');
      
    }
    
    session_start();
    
    if ($regenerate_session_id) {
      
      regenerate_session_id();
      
    }
    
    if (isset($_SESSION['last_script_load_time']) && time() - $_SESSION['last_script_load_time'] > $timeout) {
      
      session_terminate();
      
      return false;
      
    }
    
    $_SESSION['last_script_load_time'] = time();
    
    return true;
    
  }
  
  function regenerate_session_id() {
    
    $session = array();
    
    foreach ($_SESSION as $k => $v) {
      
      $session[$k] = $v;
      
    }
    
    session_destroy();
    
    session_id(bin2hex(openssl_random_pseudo_bytes(16)));
    
    session_start();
    
    foreach ($session as $k => $v) {
      
      $_SESSION[$k] = $v;
      
    }
    
  }
  
  function session_terminate() {
    
    $_SESSION = array();
    
    session_destroy();
    
    setcookie(SESSION_NAME, '', time() - 3600);
    
  }
Link to comment
Share on other sites

  • 2 weeks later...

After quite a bit of playing around with the code, I decided to post my final thoughts on the topic of secure sessions on a new website that Matt on this forum and I just launched:

http://bestpracticesfortheweb.com/articles/1/php/secure-sessions-in-php

 

Hopefully over time, the site will become a dumping ground for all the good code we've gathered over the years as well as just a place for us to share our thoughts on development, in general.

 

Any thoughts on the article or the site in general would be much appreciated.

Thanks.

Link to comment
Share on other sites

  • 4 weeks later...

Larry and Antonio,

 

Thanks for the nice comments, but I think Jon deserves almost all the credit for it right now.  He built the site (quite quickly I must add) and wrote the first post, but I did provide feedback and support.

 

My biggest contribution was probably acting as the initial inspiration for it as I was tired of going to S.O. and other sites looking for answers to certain web related questions, only to read a myriad of half informed, or downright wrong responses to the topic.  You know the kind of people who, when the OP asks something about mysqli, some arrogant a-hole tells him he should be using PDO because, well, it's easier and more powerful.  Of course, nowhere did he actually answer the question (and he also doesn't seem to have any understanding of the drawbacks of using PDO, just that it's OOP and everyone else is using it, so it must be the "thing" to use)!  I know Jon was getting tired of this as well.  We wanted to create a one-stop site where all off the best solutions for problems we have discovered over the years (and this includes a lot of Larry's as well) could be documented in one place for anyone to download and use.

 

Anyone who wants to contribute, and has discovered a good solution for a specific problem, is more than welcome to submit a post to it!

 

Matt

  • Upvote 2
Link to comment
Share on other sites

  • 6 months later...

I finally got around to start writing a session manager class using Jon's functions.

 

While I do have a lot of OOP experience, this is the first class I've written in PHP.  I wrote it in about 5 min., so there are probably some bad practices/errors here!  If anyone wants to use it, or make improvements to it, by all means, please do!

<?php
  
  class SessionManager {
    
    private $SESSION_DIR = 'd79252d7dea8e2812b4ebf29ffc603ed\\';
    
    private $SESSION_NAME = 'f7eac143c2e6c95e84a3e128e9ddcee6';
    
    static function session_init($regenerate_session_id = true, $secure_cookies_only = false, $timeout = 600) {
        
        $SITE_ROOT = $_SERVER['DOCUMENT_ROOT'];
        
        $SESSION_SAVE_PATH = $SITE_ROOT . $this->$SESSION_NAME;
        
        session_save_path($SESSION_SAVE_PATH);
        
        session_name($this->$SESSION_NAME);
        
        if ($secure_cookies_only) {
          
          ini_set('session.cookie_secure', '1');
          
        }
        
        session_start();
        
        if ($regenerate_session_id) {
          
          self::regenerate_session_id();
          
        }
        
        if (isset($_SESSION['last_script_load_time']) && time() - $_SESSION['last_script_load_time'] > $timeout) {
          
          self::session_terminate();
          
          return false;
          
        }
        
        $_SESSION['last_script_load_time'] = time();
        
        return true;
        
    }
    
    static function regenerate_session_id() {
        
        $session = array();
        
        foreach ($_SESSION as $k => $v) {
          
          $session[$k] = $v;
          
        }
        
        session_destroy();
        
        session_id(bin2hex(openssl_random_pseudo_bytes(16)));
        
        session_start();
        
        foreach ($session as $k => $v) {
          
          $_SESSION[$k] = $v;
          
        }
        
    }
    
    static function session_terminate() {
        
        $_SESSION = array();
        
        session_destroy();
        
        setcookie($this->$SESSION_NAME, '', time() - 3600);
        
    }
  
}

The main concern I have about doing it this way, and I have also noticed this in a couple other session manager classes I found online, is that there aren't any functions for adding/deleting data from the SESSION array.  It's like people use this type of class just to initialize the session or regenerate session IDs.  Maybe I am thinking too much about this, but an object is supposed to encapsulate all the functionality needed by an autonomous "thing", and in this case it's a session.  I think that all transactions with the session should be done through the session manager object and that object alone!

 

Larry or Antonio, please feel free to give any suggestions or helpful advice.

 

Thanks,

 

Matt

Link to comment
Share on other sites

Absolutely. It makes sense to me to have methods for adding, updating, getting and setting stuff, but not necessarily in the manager. Those kind of things would be better suited to a Session object. To make it sweeter, I would also have the Session object implement some interfaces for handling stuff like serialization and etc.

 

In the real world though, I've usually cheated by writing some quick wrapping around the stupid globals. Usually, you don't want error messages or similar when say a session key isn't found, so I've focused more on that kind of stuff. I don't think I actually have that code readily available, but I would link you a Gist if I did.

 

Quick usage example:

Session::start();
Session::add('key', 'value');
Session::exists('key');
Session::get('key'); // Return null, throw exception? Your choice
Session::remove('key'); // Why must $_SESSION['key'] exists for me to "delete" it? No errors on non-existing keys
Session::regenerate();

I've almost stupped doing this kind of stuff myself. No matter what kind of project you work on, you usually need this kind of functionality. Due to that, I tend to build on Laravel or even the Symfony2-stack itself. The latter we also implement custom systems on at work, so that's a bonus.

 

Let us know how it works out, Matt.

  • Upvote 1
Link to comment
Share on other sites

Good question, I had a similar question on here but in terms of it being through Yii. 

 

A follow up question on a slight tangent, Larry, when you say:

 

 

 

I would therefore take it that you wouldn't advocate using a url parameter in Yii such as

 

user/profile/1 - with 1 being the user's primary key? 

 

Or do you say that because the cookie can be altered?

 

I was thinking about this as well you could just put

 

user/member/username

 

So loading up by there username instead of their id, i guess this only applies if your members have a username though.

Link to comment
Share on other sites

Antonio,

 

Thanks for your input on this!  I just had a couple of questions:

 

 

Those kind of things would be better suited to a Session object. To make it sweeter, I would also have the Session object implement some interfaces for handling stuff like serialization and etc.

 

I'm curious why you would separate session handling functionality into a separate class?  A while back, when Jon and I were researching session best practices, I looked at the way (I think it was Zend) a framework was handling sessions, thinking that I could just copy over some code.  I was absolutely shocked!  It used not 1, not 2, NOT 3, NOT 4, but 5 classes to handle sessions!  I know it's a framework, and almost all frameworks by their very nature are pieces of bloatware that are designed to handle numerous different use cases, but this is simply ludicrous!  A session is a very simple thing when it comes down to it!  You create one, add data to it, take data out of it, and destroy it.  Why there needs to be any more than one, perhaps 2 at most, classes just amazes me.  And an interface?  Antonio, there is only ever ONE session per user visiting a web site.  Why in the world would you want to write an interface and then implement it with a class?  This kind of unnecessary abstraction is the exact reason why sites using frameworks are generally slow!  I`m not trying to be hard on you, but I really want to know what I am missing here.

 

 

Usually, you don't want error messages or similar when say a session key isn't found, so I've focused more on that kind of stuff.

 

Very good point!

 

 

Due to that, I tend to build on Laravel or even the Symfony2-stack itself.

 

Maybe Laravel has good session handling functionality, but here is one problem (among many) with using a framework for handling tasks that should be done by the developer.  I think it was OWASP which said the following (I'm paraphrasing) "You should never rely on a framework to implement the latest, or best, security when building a site."  The reason is that often times the developers who make the frameworks are either uninformed of new best practices, or just don't know about them altogether.  To illustrate my point, I looked through OWASP's security library and found a couple areas where even they were using security techniques that were about a year behind the currently recommended practices.  The message I'm trying to say here is YOU ARE ULTIMATELY RESPONSIBLE FOR YOUR SITE'S SECURITY!  If you trust a framework to do that for you, then it's like trusting a complete stranger on the street to go get money out of your bank account for you (well that's an extreme example, but you get my point).

 

On another note, you had said before that you wouldn't advise using static functions for the session manager class.  Why is that?  I thought that since there is only one session, that it would best be handled by an immutable class / singleton.  What are the drawbacks of using static functions?

 

Thanks again Antonio!

 

Matt

Link to comment
Share on other sites

  • 1 year later...
 Share

×
×
  • Create New...