Issues (1240)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

system/libraries/Session.php (14 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php defined('SYSPATH') or die('No direct access allowed.');
2
/**
3
 * Session library.
4
 *
5
 * $Id: Session.php 4073 2009-03-13 17:53:58Z Shadowhand $
6
 *
7
 * @package    Core
8
 * @author     Kohana Team
9
 * @copyright  (c) 2007-2008 Kohana Team
10
 * @license    http://kohanaphp.com/license.html
11
 */
12
class Session_Core
13
{
14
15
    // Session singleton
16
    protected static $instance;
17
18
    // Protected key names (cannot be set by the user)
19
    protected static $protect = array('session_id', 'user_agent', 'last_activity', 'ip_address', 'total_hits', '_kf_flash_');
20
21
    // Configuration and driver
22
    protected static $config;
23
    protected static $driver;
24
25
    // Flash variables
26
    protected static $flash;
27
28
    // Input library
29
    protected $input;
30
31
    /**
32
     * Singleton instance of Session.
33
     */
34
    public static function instance()
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
35
    {
36
        if (Session::$instance == null) {
37
            // Create a new instance
38
            new Session;
39
        }
40
41
        return Session::$instance;
42
    }
43
44
    /**
45
     * On first session instance creation, sets up the driver and creates session.
46
     */
47
    public function __construct()
0 ignored issues
show
__construct uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
48
    {
49
        $this->input = Input::instance();
50
51
        // This part only needs to be run once
52
        if (Session::$instance === null) {
53
            // Load config
54
            Session::$config = Kohana::config('session');
55
56
            // Makes a mirrored array, eg: foo=foo
57
            Session::$protect = array_combine(Session::$protect, Session::$protect);
58
59
            // Configure garbage collection
60
            ini_set('session.gc_probability', (int) Session::$config['gc_probability']);
61
            ini_set('session.gc_divisor', 100);
62
            ini_set('session.gc_maxlifetime', (Session::$config['expiration'] == 0) ? 86400 : Session::$config['expiration']);
63
64
            // Create a new session
65
            $this->create();
66
67
            if (Session::$config['regenerate'] > 0 and ($_SESSION['total_hits'] % Session::$config['regenerate']) === 0) {
68
                // Regenerate session id and update session cookie
69
                $this->regenerate();
70
            } else {
71
                // Always update session cookie to keep the session alive
72
                cookie::set(Session::$config['name'], $_SESSION['session_id'], Session::$config['expiration']);
73
            }
74
75
            // Close the session just before sending the headers, so that
76
            // the session cookie(s) can be written.
77
            Event::add('system.send_headers', array($this, 'write_close'));
78
79
            // Make sure that sessions are closed before exiting
80
            register_shutdown_function(array($this, 'write_close'));
81
82
            // Singleton instance
83
            Session::$instance = $this;
84
        }
85
86
        Kohana::log('debug', 'Session Library initialized');
87
    }
88
89
    /**
90
     * Get the session id.
91
     *
92
     * @return  string
93
     */
94
    public function id()
0 ignored issues
show
id uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
This method's name is shorter than the configured minimum length of 3 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
95
    {
96
        return $_SESSION['session_id'];
97
    }
98
99
    /**
100
     * Create a new session.
101
     *
102
     * @param   array  variables to set after creation
103
     * @return  void
104
     */
105
    public function create($vars = null)
0 ignored issues
show
create uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
106
    {
107
        // Destroy any current sessions
108
        $this->destroy();
109
110
        if (Session::$config['driver'] !== 'native') {
111
            // Set driver name
112
            $driver = 'Session_'.ucfirst(Session::$config['driver']).'_Driver';
113
114
            // Load the driver
115 View Code Duplication
            if (! Kohana::auto_load($driver)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
                throw new Kohana_Exception('core.driver_not_found', Session::$config['driver'], get_class($this));
117
            }
118
119
            // Initialize the driver
120
            Session::$driver = new $driver();
121
122
            // Validate the driver
123
            if (! (Session::$driver instanceof Session_Driver)) {
124
                throw new Kohana_Exception('core.driver_implements', Session::$config['driver'], get_class($this), 'Session_Driver');
125
            }
126
127
            // Register non-native driver as the session handler
128
            session_set_save_handler(
129
                array(Session::$driver, 'open'),
130
                array(Session::$driver, 'close'),
131
                array(Session::$driver, 'read'),
132
                array(Session::$driver, 'write'),
133
                array(Session::$driver, 'destroy'),
134
                array(Session::$driver, 'gc')
135
            );
136
        }
137
138
        // Validate the session name
139
        if (! preg_match('~^(?=.*[a-z])[a-z0-9_]++$~iD', Session::$config['name'])) {
140
            throw new Kohana_Exception('session.invalid_session_name', Session::$config['name']);
141
        }
142
143
        // Name the session, this will also be the name of the cookie
144
        session_name(Session::$config['name']);
145
146
        // Set the session cookie parameters
147
        session_set_cookie_params(
148
            Session::$config['expiration'],
149
            Kohana::config('cookie.path'),
150
            Kohana::config('cookie.domain'),
151
            Kohana::config('cookie.secure'),
152
            Kohana::config('cookie.httponly')
153
        );
154
155
        // Start the session!
156
        session_start();
157
158
        // Put session_id in the session variable
159
        $_SESSION['session_id'] = session_id();
160
161
        // Set defaults
162
        if (! isset($_SESSION['_kf_flash_'])) {
163
            $_SESSION['total_hits'] = 0;
164
            $_SESSION['_kf_flash_'] = array();
165
166
            $_SESSION['user_agent'] = Kohana::$user_agent;
167
            $_SESSION['ip_address'] = $this->input->ip_address();
168
        }
169
170
        // Set up flash variables
171
        Session::$flash =& $_SESSION['_kf_flash_'];
172
173
        // Increase total hits
174
        $_SESSION['total_hits'] += 1;
175
176
        // Validate data only on hits after one
177
        if ($_SESSION['total_hits'] > 1) {
178
            // Validate the session
179
            foreach (Session::$config['validate'] as $valid) {
180
                switch ($valid) {
181
                    // Check user agent for consistency
182
                    case 'user_agent':
183
                        if ($_SESSION[$valid] !== Kohana::$user_agent) {
184
                            return $this->create();
185
                        }
186
                    break;
187
188
                    // Check ip address for consistency
189
                    case 'ip_address':
190
                        if ($_SESSION[$valid] !== $this->input->$valid()) {
191
                            return $this->create();
192
                        }
193
                    break;
194
195
                    // Check expiration time to prevent users from manually modifying it
196
                    case 'expiration':
197
                        if (time() - $_SESSION['last_activity'] > ini_get('session.gc_maxlifetime')) {
198
                            return $this->create();
199
                        }
200
                    break;
201
                }
202
            }
203
        }
204
205
        // Expire flash keys
206
        $this->expire_flash();
207
208
        // Update last activity
209
        $_SESSION['last_activity'] = time();
210
211
        // Set the new data
212
        Session::set($vars);
213
    }
214
215
    /**
216
     * Regenerates the global session id.
217
     *
218
     * @return  void
219
     */
220
    public function regenerate()
0 ignored issues
show
regenerate uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
regenerate uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
221
    {
222
        if (Session::$config['driver'] === 'native') {
223
            // Generate a new session id
224
            // Note: also sets a new session cookie with the updated id
225
            session_regenerate_id(true);
226
227
            // Update session with new id
228
            $_SESSION['session_id'] = session_id();
229
        } else {
230
            // Pass the regenerating off to the driver in case it wants to do anything special
231
            $_SESSION['session_id'] = Session::$driver->regenerate();
232
        }
233
234
        // Get the session name
235
        $name = session_name();
236
237
        if (isset($_COOKIE[$name])) {
238
            // Change the cookie value to match the new session id to prevent "lag"
239
            $_COOKIE[$name] = $_SESSION['session_id'];
240
        }
241
    }
242
243
    /**
244
     * Destroys the current session.
245
     *
246
     * @return  void
247
     */
248
    public function destroy()
0 ignored issues
show
destroy uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
249
    {
250
        if (session_id() !== '') {
251
            // Get the session name
252
            $name = session_name();
253
254
            // Destroy the session
255
            session_destroy();
256
257
            // Re-initialize the array
258
            $_SESSION = array();
259
260
            // Delete the session cookie
261
            cookie::delete($name);
262
        }
263
    }
264
265
    /**
266
     * Runs the system.session_write event, then calls session_write_close.
267
     *
268
     * @return  void
269
     */
270
    public function write_close()
271
    {
272
        static $run;
273
274
        if ($run === null) {
275
            $run = true;
276
277
            // Run the events that depend on the session being open
278
            Event::run('system.session_write');
279
280
            // Expire flash keys
281
            $this->expire_flash();
282
283
            // Close the session
284
            session_write_close();
285
        }
286
    }
287
288
    /**
289
     * Set a session variable.
290
     *
291
     * @param   string|array  key, or array of values
292
     * @param   mixed         value (if keys is not an array)
293
     * @return  false|null
294
     */
295
    public function set($keys, $val = false)
0 ignored issues
show
set uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
296
    {
297
        if (empty($keys)) {
298
            return false;
299
        }
300
301
        if (! is_array($keys)) {
302
            $keys = array($keys => $val);
303
        }
304
305
        foreach ($keys as $key => $val) {
306
            if (isset(Session::$protect[$key])) {
307
                continue;
308
            }
309
310
            // Set the key
311
            $_SESSION[$key] = $val;
312
        }
313
    }
314
315
    /**
316
     * Set a flash variable.
317
     *
318
     * @param   string|array  key, or array of values
319
     * @param   mixed         value (if keys is not an array)
320
     * @return  false|null
321
     */
322
    public function set_flash($keys, $val = false)
323
    {
324
        if (empty($keys)) {
325
            return false;
326
        }
327
328
        if (! is_array($keys)) {
329
            $keys = array($keys => $val);
330
        }
331
332
        foreach ($keys as $key => $val) {
333
            if ($key == false) {
334
                continue;
335
            }
336
337
            Session::$flash[$key] = 'new';
338
            Session::set($key, $val);
339
        }
340
    }
341
342
    /**
343
     * Freshen one, multiple or all flash variables.
344
     *
345
     * @param   string  variable key(s)
346
     * @return  void
347
     */
348
    public function keep_flash($keys = null)
349
    {
350
        $keys = ($keys === null) ? array_keys(Session::$flash) : func_get_args();
351
352
        foreach ($keys as $key) {
353
            if (isset(Session::$flash[$key])) {
354
                Session::$flash[$key] = 'new';
355
            }
356
        }
357
    }
358
359
    /**
360
     * Expires old flash data and removes it from the session.
361
     *
362
     * @return  void
363
     */
364
    public function expire_flash()
0 ignored issues
show
expire_flash uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
365
    {
366
        static $run;
367
368
        // Method can only be run once
369
        if ($run === true) {
370
            return;
371
        }
372
373
        if (! empty(Session::$flash)) {
374
            foreach (Session::$flash as $key => $state) {
375
                if ($state === 'old') {
376
                    // Flash has expired
377
                    unset(Session::$flash[$key], $_SESSION[$key]);
378
                } else {
379
                    // Flash will expire
380
                    Session::$flash[$key] = 'old';
381
                }
382
            }
383
        }
384
385
        // Method has been run
386
        $run = true;
387
    }
388
389
    /**
390
     * Get a variable. Access to sub-arrays is supported with key.subkey.
391
     *
392
     * @param   string  variable key
393
     * @param   mixed   default value returned if variable does not exist
394
     * @return  mixed   Variable data if key specified, otherwise array containing all session data.
395
     */
396
    public function get($key = false, $default = false)
0 ignored issues
show
get uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
397
    {
398
        if (empty($key)) {
399
            return $_SESSION;
400
        }
401
402
        $result = isset($_SESSION[$key]) ? $_SESSION[$key] : Kohana::key_string($_SESSION, $key);
403
404
        return ($result === null) ? $default : $result;
405
    }
406
407
    /**
408
     * Get a variable, and delete it.
409
     *
410
     * @param   string  variable key
411
     * @param   mixed   default value returned if variable does not exist
412
     * @return  mixed
413
     */
414
    public function get_once($key, $default = false)
415
    {
416
        $return = Session::get($key, $default);
417
        Session::delete($key);
418
419
        return $return;
420
    }
421
422
    /**
423
     * Delete one or more variables.
424
     *
425
     * @param   string  variable key(s)
426
     * @return  void
427
     */
428
    public function delete($keys)
0 ignored issues
show
The parameter $keys is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
delete uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
429
    {
430
        $args = func_get_args();
431
432
        foreach ($args as $key) {
433
            if (isset(Session::$protect[$key])) {
434
                continue;
435
            }
436
437
            // Unset the key
438
            unset($_SESSION[$key]);
439
        }
440
    }
441
} // End Session Class
442