aboutsummaryrefslogtreecommitdiffhomepage
path: root/inc/Session.class.php
blob: 06fa6a8ecfa82a593e56345dda19325a69586b63 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php
/**
 * Session management class
 * http://www.developpez.net/forums/d51943/php/langage/sessions/
 * http://sebsauvage.net/wiki/doku.php?id=php:session
 * http://sebsauvage.net/wiki/doku.php?id=php:shaarli
 *
 * Features:
 * - Everything is stored on server-side (we do not trust client-side data,
 *   such as cookie expiration)
 * - IP addresses + user agent are checked on each access to prevent session
 *   cookie hijacking (such as Firesheep)
 * - Session expires on user inactivity (Session expiration date is
 *   automatically updated everytime the user accesses a page.)
 * - A unique secret key is generated on server-side for this session
 *   (and never sent over the wire) which can be used
 *   to sign forms (HMAC) (See $_SESSION['uid'] )
 * - Token management to prevent XSRF attacks.
 *
 * TODO:
 * - log login fail
 * - prevent brute force (ban IP)
 *
 * HOWTOUSE:
 * - Just call Session::init(); to initialize session and
 *   check if connected with Session::isLogged()
 */

class Session
{
    // If the user does not access any page within this time,
    // his/her session is considered expired (in seconds).
    public static $inactivity_timeout = 3600;
    private static $_instance;

    // constructor
    private function __construct()
    {
        // Use cookies to store session.
        ini_set('session.use_cookies', 1);
        // Force cookies for session  (phpsessionID forbidden in URL)
        ini_set('session.use_only_cookies', 1);
        if (!session_id()){
            // Prevent php to use sessionID in URL if cookies are disabled.
            ini_set('session.use_trans_sid', false);
            session_start('poche');
        }
    }

    // initialize session
    public static function init()
    {
        if (!isset(self::$_instance)) {
            self::$_instance = new Session();
        }
    }

    // Returns the IP address, user agent and language of the client
    // (Used to prevent session cookie hijacking.)
    private static function _allInfos()
    {
        $infos = $_SERVER["REMOTE_ADDR"];
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $infos.=$_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        if (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $infos.='_'.$_SERVER['HTTP_CLIENT_IP'];
        }
        $infos.='_'.$_SERVER['HTTP_USER_AGENT'];
        $infos.='_'.$_SERVER['HTTP_ACCEPT_LANGUAGE'];
        return sha1($infos);
    }

    // Check that user/password is correct and init some SESSION variables.
    public static function login($login,$password,$login_test,$password_test,
                                 $pValues = array())
    {
        foreach ($pValues as $key => $value) {
            $_SESSION[$key] = $value;
        }
        if ($login==$login_test && $password==$password_test){
            // generate unique random number to sign forms (HMAC)
            $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand());
            $_SESSION['info']=Session::_allInfos();
            $_SESSION['username']=$login;
            // Set session expiration.
            $_SESSION['expires_on']=time()+Session::$inactivity_timeout;
            return true;
        }
        return false;
    }

    // Force logout
    public static function logout()
    {
        unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on']);
    }

    // Make sure user is logged in.
    public static function isLogged()
    {
        if (!isset ($_SESSION['uid'])
            || $_SESSION['info']!=Session::_allInfos()
            || time()>=$_SESSION['expires_on']){
            Session::logout();
            return false;
        }
        // User accessed a page : Update his/her session expiration date.
        $_SESSION['expires_on']=time()+Session::$inactivity_timeout;
        return true;
    }

    // Returns a token.
    public static function getToken()
    {
        if (!isset($_SESSION['tokens'])){
            $_SESSION['tokens']=array();
        }
        // We generate a random string and store it on the server side.
        $rnd = sha1(uniqid('',true).'_'.mt_rand());
        $_SESSION['tokens'][$rnd]=1;
        return $rnd;
    }

    // Tells if a token is ok. Using this function will destroy the token.
    // return true if token is ok.
    public static function isToken($token)
    {
        if (isset($_SESSION['tokens'][$token]))
        {
            unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
            return true; // Token is ok.
        }
        return false; // Wrong token, or already used.
    }
}