Decrease responsibility of a class

2

Recently I had the need to work with object-oriented sessions and created the following class:

<?php
/**
 * @author Mateus Demboski <[email protected]>
 * @link <https://github.com/mateusdemboski/PHPsessionManager>
 */

#namespace Demboski;

/**
 * Class Session
 */
class Session {

    /**
     * Verify if a PHP session already been started.
     *
     * @return bool
     */
    public static function isStarted(){
        return session_status() == PHP_SESSION_ACTIVE;
    }

    /**
     * Verify if a key exists on session.
     *
     * @param null $session_key
     * @return bool
     */
    public static function exists($session_key = null){
        return isset($_SESSION[$session_key]);
    }

    /**
     * Initialize session data. If session has already started in PHP the
     * script generate a exception.
     *
     * @return bool
     * @throws \Exception
     */
    public static function start(){
        if(self::isStarted())
            throw new \Exception('A session has already started in PHP!');

        return session_start();
    }

    /**
     * Destroys all data registered to a session.
     *
     * @return bool
     */
    public static function destroy(){
        return session_destroy();
    }

    /**
     * Get the value by key from current session.
     *
     * @param string|int $session_key
     * @param bool $unserialize
     * @return string|null
     */
    public static function get($session_key, $unserialize = false){
        if(!self::isStarted())
            throw new \BadFunctionCallException('A session in PHP need be started!');

        if(self::exists($session_key))

            if($unserialize)
                return unserialize(base64_decode($_SESSION[$session_key]));

            else
                return $_SESSION[$session_key];

        else return null;
    }

    /**
     * Assign a value from key in the current session.
     *
     * @param string $session_key
     * @param mixed $value
     * @param bool $serialize
     * @return bool
     */
    public static function set($session_key, $value, $serialize = false){
        if(!self::isStarted())
            throw new \BadFunctionCallException('A session in PHP need be started!');


        if($serialize) $value = base64_encode(serialize($value));

        $_SESSION[$session_key] = $value;

        return $_SESSION[$session_key] == $value;
    }

    /**
     * Delete an item from session by key.
     *
     * @param $session_key
     * @return bool
     */
    public static function delete($session_key){
        if(!self::isStarted())
            throw new \BadFunctionCallException('A session in PHP need be started!');

        $return = true;

        if(self::exists($session_key))
            unset($_SESSION[$session_key]);
        else
            $return = false;

        return $return;
    }

    /**
     * Destroys all data registered to a session and start a new session.
     *
     * @return bool
     */
    public static function clean(){
        if(!self::isStarted())
            throw new \BadFunctionCallException('A session in PHP need be started!');

        self::destroy();
        self::start();
        return true;
    }

    /**
     * Set the current session name.
     * The session name references the name of the session, which is
     * used in cookies and URLs (e.g. PHPSESSID).
     *
     * @param null $session_name
     * @return string
     */
    public static function setName($session_name = null){
        return session_name($session_name);
    }

    /**
     * Get the current session name.
     * The session name references the name of the session, which is
     * used in cookies and URLs (e.g. PHPSESSID).
     *
     * @return string
     */
    public static function getName(){
        return session_name();
    }

    /**
     * Set the current session id
     *
     * @param null $session_id
     * @return string
     */
    public static function setId($session_id = null){
        return session_id($session_id);
    }

    /**
     * Get the current session id
     *
     * @return string
     */
    public static function getId(){
        return session_id();
    }

    /**
     * Update the current session id with a newly generated one.
     *
     * @param bool $deleteOldSession
     * @return bool
     */
    public static function regenerateId($deleteOldSession = false){
        return session_regenerate_id($deleteOldSession);
    }

    /**
     * prevent the session hijacking
     *
     * @param string $session_key Default is "PREVENT_SESSION_HIJACKING".
     * @param array $hashAlgo Is the Name of selected hashing algorithm (e.g. "md5", "sha256", "haval160,4", etc..)
     * @param int|string $exit Default is 1.
     */
    public static function preventHijacking($session_key = 'PREVENT_SESSION_HIJACKING',
                                            $hashAlgo = 'md5',
                                            $exit = 1){
        $hashData = $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR'];
        $hash = hash($hashAlgo, $hashData);
        if(self::isStarted() && !self::exists($session_key))
            self::set($session_key, $hash );
        elseif(self::isStarted() || !self::exists($session_key) || self::get($session_key) != $hash ){
            exit($exit);
        }
    }
}

But it seems to me to have a lot of responsibilities, for example, the preventHijacking method is a security method for sessions and I do not seem to be in the right place, but at the same time I find it unnecessary to create a new class inside namespace for this method only.

What could be done in this case? How could this class be improved?

    
asked by anonymous 28.05.2015 / 15:09

1 answer

2

Regarding the class I do not see any problem and the responsibility described in the question does not understand so. The best answer can only be delivered after analysis of the project where it will be inserted.

Preventing session hijaking is a recurring subject, approaches are several but experience has led me to address some methods:

1) Always use https - this is because a lot of problem associated with session theft is filtered.

2) regenerating session_id whenever possible is equally important especially with each new "login" and "logout" if the project is the case.

3) I recommend a read on my answer at Session Hijacking Prevention

Finally I recommend using a TOKEN that is generated every request , also kept in session.

All together makes it very difficult and prevents session theft in a competent way.

    
28.05.2015 / 17:19