2
\$\begingroup\$

The goal is to try and make an everlasting SESSION without too much or unnecessary scripting for updating of sessions. And at the same time to avoid session collision as session collisions could lead to 2 users trying to make use of the same session. That would not look pretty! And it does happen. Also for websites that use different language sub-domains, it would be useful if session did not change so that you can easily go from one sub-domain to another without requiring new sessions.

STEP 0:

function getUserIP(){
    $client  = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote  = $_SERVER['REMOTE_ADDR'];

    if(filter_var($client, FILTER_VALIDATE_IP)){
        $ip = $client;
    }else
    if(filter_var($forward, FILTER_VALIDATE_IP)){
        $ip = $forward;
    }else{
        $ip = $remote;
    }
    return $ip;
}
$ip = getUserIP();

STEP 1:

ini_set('session.gc_probability', 0);// 0% probability of purging session log files, in this case on startup we preventing sessions from ever being deleted!
session_set_cookie_params(0, '/', '.website.com');// allow same session to be set across sub-domains!
session_name('session');// now make sure that the same session will not be regenerated across sub-domains and stay the same!
session_save_path($_SERVER['DOCUMENT_ROOT'].'/SESSION');//finally sessions are stored in a folder of choice in say public_html folder..
session_start();// we allow sessions to be read or changed..

STEP 2:

if(isset($_SESSION['ip'])){// if IP session in session log exist, do..
    if($ip!=$_SESSION['ip']){// if the current IP is not in the session log, then user privileges hasn't been confirmed!
        session_regenerate_id();// make sure that current visitor will be forced to use a different session_id! // new session copy is generated!
        session_destroy();// new session copy will be cleansed from previous data to be ready for use!
        header('Location: .');// reload the current page and to begin using a new session algorithm!
    }// SESSION collision has now been avoided and replaced with SESSION+IP collision where chances of that are pretty much ZERO!!!
    // IP is checked first, even if collision does occur, it will not allow to use it because of the missing IP..
    // that means someone must be in a public place that uses same IP for all PC's and within that amount of PCs a collision can occur!
}else{// if session doesn't exist, start new log!
    $_SESSION['ip']=$ip;// visitor session log file has been updated!
    echo 'NEW SESSION!<br>';
}

Is this a good solution? Is it a great solution? Is it the best solution? What do you guys think? :) Note, that I didn't include the cleaning up process in this scenario, so you should use your imagination! But with this script you shouldn't even be needing a script to clean up sessions. All you'll need is to go to FileZilla, enter SESSION folder, select 1 file, press ctrl+a to select all session log files and then delete them all once a month or even once a year or so!? Also the storage directory for SESSIONS is just an example that you can put them in some nearby location closer to your development folder. But public_html is kinda PUBLIC and therefore you should use it along with .htaccess file and restrict access to the SESSIONS folder to secure it.

\$\endgroup\$
  • \$\begingroup\$ Why do you think a session should be everlasting in the first place? If you truly need to persist data in a permanent fashion related to a user, sessions are not the way to do it. What are you really trying to do? Why is an IP address something you are using for determining "user privileges"? \$\endgroup\$ – Mike Brant Mar 24 '17 at 22:32
  • 1
    \$\begingroup\$ Why would you EVER expose session data files in a publicly accessible directory? I think perhaps you have serious misconception for what session data is and what it is meant to be used for. \$\endgroup\$ – Mike Brant Mar 24 '17 at 22:38
  • \$\begingroup\$ That was kinda an example. Sure, sessions should not be everlasting indeed. But this method which is basically 1 line, provides an alternative solution to messing with expiration date and time. So to avoid all that, instead of figuring out how to better expire a session in time before something bad happens, I decided to improve security for it so it can be used for much longer. So basically instead of going left, I went right. Am I right? :) \$\endgroup\$ – Vadim Cool Mar 24 '17 at 22:48
  • \$\begingroup\$ No. This solution is totally insecure. Here is good starting point for handling sessions securely php.net/manual/en/features.session.security.management.php \$\endgroup\$ – Mike Brant Mar 24 '17 at 22:50
  • \$\begingroup\$ As for the choice of where to place session is up to an individual. This was simply an example to show people that they can take control of their sessions into their own hands! Where you save them actually depends on preferences and should not be a security question or misconception of use. Because those people who care about their websites, they will make sure to begin with that .htaccess will take care of the folder security and the accessible files for the public. And if website gets hacked, well then at this point sessions most likely will reveal even less than the entire website!! :D \$\endgroup\$ – Vadim Cool Mar 24 '17 at 22:51
1
\$\begingroup\$

Since nobody else has chimed in here, I figured I would elaborate on my comments above. If your stated goal is to:

  • have sessions that last indefinitely
  • have sessions that are more secure than default settings
  • have sessions that have have less chance of collision than default settings

Then this is the wrong approach. You are actually not meeting any of these goals, and in fact are making security and chance of collision worse.

First, these sessions will not be indefinite. You are setting session cookie lifetime with value of 0 which means that, if the browser is compliant with this setting, the cookie will only last as long as the browser is open. If that user closes their browser and then opens it back up 10 minutes later, they will get a new session. There is no setting that will make a session last forever, as sessions are not really designed to last forever. If you need data to persist between what truly are "sessions" then you need to look for another solution. I am not suggesting you change this setting at all, as for most use cases when using sessions as intended, a value of 0 for cookie lifetime is a reasonable setting.


So, now that we have established that you are not truly getting "everlasting" sessions, let's get into the security aspects.

Here are a few PHP documentation links I will refer to:


We will start with garbage collection. Since you are not getting long-lasting sessions, that fact that you want to collect session data files (or database records if one were to use a database to store the data) indefinitely, means that you are, in essence, accumulating attack vectors against your application. Ideally you should use an appropriate session lifetime and an aggressive approach to invalidating and pruning old records to minimize security risk. One comment from the session.gc_maxlifetime section of the securing INI link above seems very pertinent here:

If auto login feature is required, implement your own secure auto login feature. Never use long life session ID for it.

Long sessions should not be purposed for long-term data persistence or used for authentication/authorization as it seems you are trying to do.


As I mentioned earlier accumulating these session files is like accumulating attack vectors, as you increase the opportunity for someone to execute a session hijacking or session fixation attack against your application. This coupled with the fact that you open the application to using session cookies over non-secure (HTTP) connection, means it would be trivial for a packet sniffer or man in the middle to grab a session ID from a legitimate user's request and use it FOREVER.

And while destroying/regenerating session id's across IP change boundaries is a reasonable security measure, it is by no means enough. That attacker could be sitting in a Starbucks along with the legitimate user using a wifi network which has the same exact IP address. A sophisticated attacker can also easily spoof their IP address.

Also, keep in mind that there are some legitimate use cases where a user might change IP address during a session (a user on a mobile device for example), so while, IP address can be used as one of the triggers for session invalidation, if you use some of the other takeaways about handling session securely, you might decide that it's importance as a criteria for session invalidation might not be worth a potentially bad user experiences if you had a high number of mobile users.


Accumulating these session files also does increase your risk of a session collision. Now that may be a pretty minute risk on a website with low traffic level anyway, but you are certainly making the probability of it happening worse, not better, with your approach. And the IP check has nothing to do with mitigating against session id collision as mentioned in your comments. That IP value is stored inside the session data and in no way helps mitigate a collision on the session id itself.


Let's talk about the session file save path. I know there was some back and forth on this in the comments, with me suggesting that putting these files in a web directory is a bad security practice. You are right that one could limit access to this directory in other ways, but why would you want to introduce a security vulnerability that you need an additional security measure to mitigate? You are making your application security more complex and more fragile to someone not setting things up properly than it has to be.

Additionally, it just makes no practical sense to be putting this data into your application web directory anyway, just from a straight separation of concerns/access standpoint. One doesn't typically configure database files, application logging, or other similar functionality that might read-write system files to do so into the application space, so why would you do this with session data?

Ideally, you write session data into a directory only available to the root user or user under which your application is running under to access and you don't let administrators working with the production system have root/sudo access in production unless absolutely necessary.


You should be using session.use_strict_mode if not specified as such in your ini file (this is not shown here obviously,so I am not sure what your current approach is). This will help mitigate against session fixation, but will not help if an attacker uses one of the sessions id's you are collecting as cruft.


If you are using PHP 7.1, consider using session_create_id() to establish better connection between indvidual user and their session id. This allows allows better usage of prefix index for database lookups if ever using a relational database as session storage medium.


Even for a case of using long sessions (or true browser-controlled session lengths as you are doing), you should regenerate session id at regular intervals to mitigate against session fixation/hijacking. This means you have to start managing a timestamp in the session data. There really is no way around this in PHP sessions. I know one of your stated goals was to not have to get into this, but there really is no alternative if you want your sessions to be secure. Please read the "Session ID Regeneration" section of the second link given above.

There is a pertinent quote there:

Developer must NOT rely on session ID expiration by session.gc_maxlifetime. Attackers may access victim's session ID periodically to prevent expiration and keep exploiting victim's session ID including authenticated sessions.

Instead, you must implement time-stamp based session data management by yourself.

So a bad system would rely on garbage collection alone to provide mitigation against session fixation. A really bad system would not use garbage collection at all.

Again... you have to use timestamps if you want secure sessions.


Additionally, session_regenerate_id() combined with session_destroy() in PHP doesn't magically work by itself. See the warning note in the session_regenerate_id() documentation:

You should not destroy old session data immediately, but should use destroy time-stamp and control access to old session ID. Otherwise, concurrent access to page may result in inconsistent state, or you may have lost session, or it may cause client(browser) side race condition and may create many session ID needlessly. Immediate session data deletion disables session hijack attack detection and prevention also.

Again... you have to use timestamps if you want secure sessions.


Continuing in the area of session data management. Let's talk data deletion. Please heed this text from the "Session Data Deletion" section of the second link above:

Obsolete session data is better to be removed as soon as possible. However, active sessions MUST NOT be removed immediately. To satisfy these requirements, you MUST implement time-stamp based session data management by yourself.

Set and manage expiration time-stamp in $_SESSION. Prohibit access to obsolete session data. When obsolete session data access is detected, it is advised to remove all authenticated status from the user's sessions and force them to re-authenticated. Obsolete session data access could be an attack. To do this, you must keep track active sessions per user.

In short, do not destroy session data by session_regenerate_id() nor session_destroy(), but use time-stamp to control access to session data. Let session_gc() to remove obsolete data from session data storage.

Again... you have to use timestamps if you want secure sessions.


session_name('session');// now make sure that the same session will not be regenerated across sub-domains and stay the same!

This doesn't really do what the comment says it does. This function simply determines that name of the session cookie to be used. This doesn't guarantee any cross-domain interactivity of the cookie unless this same name is used for the cookie in all those sub-domains. I think naming your sessions is totally fine, but this is really not necessary to achieve this effect. For example, if every subdomain was a PHP app with the same INI setting for this, this line would be unneccessary. Similarly, if you had other subdomains that were not PHP apps, this code here does nothing to help you, as you would need to use whatever means the language in use on that subdomain uses to set this cookie name.


If all of this seems overly complex to manage in a secure manner, that is understandable. As I said in my comments to the post above, PHP does not make secure session management easy in an out of the box manner. It requires work on the part of the developer.

You might consider using a good session management library if you want to simply drop some functionality into your application and not worry so more about the minutiae of managing the sessions.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Well that was better!! Thanks! 1. Obviously I made 1 huge mistake. I didn't realize I was USING THE G*D DAMN COOKIES!!! :D This is unforgivable! As soon as I checked my cookies tab in firebug it lit up like x-mas tree!!! Never use COOKIES for security unless they at least are linked to IP. 2. But as you pointed out that IP can be spoofed, then who cares about collision! We're already in trouble. Although I must disagree with you about IP being inside a SESSION file. Because I didn't actually prevent the SESSION collision, but I did force it to be regenerated on collision! \$\endgroup\$ – Vadim Cool Mar 27 '17 at 22:53
  • \$\begingroup\$ 3. This means that in theory SESSIONS have indeed only short range uses and it is probably easier to make your OWN session creator script which will work almost the same way, but will store up to 128bit or 256bit security sessions. This way the chance of collision will be much lower and we will be able to store them the way we like, across any domain or sub-domain as they will make use of the same folder and will be read the way we tell them to be read! So I guess if others can't do it for you, you must do it yourself! Time for session reinvention. This should be fun. NOT. STUPID! \$\endgroup\$ – Vadim Cool Mar 27 '17 at 22:53
  • \$\begingroup\$ 4. But then again, why go trough all that trouble making sessions when at this rate we may as well just stick to the SQL database only. And then we can update all of the settings in there right away without any mixtures SESSION + SQL database. So yeah at this point there is no 1 line fix as SESSIONS as I see them right now are BROKEN to begin with. The entire fundamental structure should be re-written at this point. Then the time stamp needs to be checked vs. SQL saved data+PHP server data probably etc.. or something. RIP. And here I hoped for that this headache could be avoided. \$\endgroup\$ – Vadim Cool Mar 27 '17 at 23:05
  • \$\begingroup\$ 5. Session management library is a good suggestion. Maybe it is also an alternative solution rather than code your own. But I'm the kind of guy that rarely use the stuff others create as I would like to fully understand what I'm doing and also then I can easily change something. Although inspiration couldn't hurt. But for now I think I already can figure out a bunch of solutions on my own. Something that hopefully won't take too long to write. But I still think it sucks that IP can't be used as even a half way secure solution. IPs get spoofed, cookies get edited. I hate this world!!! \$\endgroup\$ – Vadim Cool Mar 27 '17 at 23:19
  • \$\begingroup\$ @VadimCool Cookies are actually the preferred way to use sessions vs in query string. Much more secure. Again, perhaps you are not really fully grasping how sessions with cookies work. The only thing that is set in the cookie is the session ID. all other session data is stored in the application via file system, memcache, database, or whatever you use as a storage mechanism and should be able to be considered secure if proper precautions are taken to secure that data. The session data itself is never sent between the application an the client. \$\endgroup\$ – Mike Brant Mar 28 '17 at 1:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.