Passed
Push — development ( 032ead...866be2 )
by Mirco
01:47
created

SessionDataCookie::set()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 3
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/***************************************************************************
3
 *  For license information see doc/license.txt
4
 *
5
 *  Unicode Reminder メモ
6
 *
7
 *  Session data handling with cookies
8
 *  See doc/cookies.txt for more information in cookies.
9
 ***************************************************************************/
10
11
namespace Oc\Session;
12
13
class SessionDataCookie implements SessionDataInterface
14
{
15
    public $changed = false;
16
    public $values = [];
17
18
    /**
19
     * SessionDataCookie constructor.
20
     */
21 View Code Duplication
    public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct 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...
Duplication introduced by
This method seems to be duplicated in 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...
22
    {
23
        global $opt;
24
25
        if (isset($_COOKIE[$opt['session']['cookiename'] . 'data'])) {
26
            //get the cookievars-array
27
            $decoded = base64_decode($_COOKIE[$opt['session']['cookiename'] . 'data'], true);
28
29
            if ($decoded !== false) {
30
                // TODO replace by safe function
31
                $this->values = @unserialize($decoded); // bad
0 ignored issues
show
Security Object Injection introduced by
$decoded can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_COOKIE, and $_COOKIE[$opt['session']['cookiename'] . 'data'] is decoded by base64_decode(), and $decoded is assigned
    in htdocs/src/Oc/Session/SessionDataCookie.php on line 27

Preventing Object Injection Attacks

If you pass raw user-data to unserialize() for example, this can be used to create an object of any class that is available in your local filesystem. For an attacker, classes that have magic methods like __destruct or __wakeup are particularly interesting in such a case, as they can be exploited very easily.

We recommend to not pass user data to such a function. In case of unserialize, better use JSON to transfer data.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
32
                //$this->values = @json_decode($decoded, true); // safe
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
33
                //print_r($this->values);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
34
                if (!is_array($this->values)) {
35
                    $this->values = [];
36
                }
37
            } else {
38
                $this->values = [];
39
            }
40
        }
41
    }
42
43
    /**
44
     * @param $name
45
     * @param $value
46
     * @param null $default
47
     */
48
    public function set($name, $value, $default = null)
49
    {
50
        // Store cookie value in internal array. OcSmarty will call this->header()
51
        // to actually set the cookie.
52
        if (!isset($this->values[$name]) || $this->values[$name] != $value) {
53
            if ($value == $default) {
54
                if (isset($this->values[$name])) {
55
                    unset($this->values[$name]);
56
                    $this->changed = true;
57
                }
58
            } else {
59
                $this->values[$name] = $value;
60
                $this->changed = true;
61
            }
62
        }
63
    }
64
65
    /**
66
     * @param $name
67
     * @param null $default
68
     *
69
     * @return mixed|null
70
     */
71
    public function get($name, $default = null)
72
    {
73
        return isset($this->values[$name]) ? $this->values[$name] : $default;
74
    }
75
76
    /**
77
     * @param $name
78
     *
79
     * @return bool
80
     */
81
    public function is_set($name)
82
    {
83
        return isset($this->values[$name]);
84
    }
85
86
    /**
87
     * @param $name
88
     */
89 View Code Duplication
    public function un_set($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
90
    {
91
        if (isset($this->values[$name])) {
92
            unset($this->values[$name]);
93
            $this->changed = true;
94
        }
95
    }
96
97
    public function header()
98
    {
99
        global $opt;
100
101
        if ($this->changed === true) {
102
103
            $value = false;
104
            if (count($this->values) > 0) {
105
                // TODO replace by safe function
106
                $value = base64_encode(serialize($this->values)); // bad
107
                //$value = base64_encode(json_encode($this->values)); // safe
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
108
            }
109
            // https used for request and https is available, then set cookie https only
110
            $https_session = $opt['page']['https']['active']
111
                && $opt['page']['https']['mode'] != HTTPS_DISABLED
112
                && $this->is_set('sessionid') // only force https while login
113
                && !empty($this->get('sessionid'));
114
115
            setcookie(
116
                $opt['session']['cookiename'] . 'data',
117
                $value,
118
                time() + 365 * 24 * 60 * 60,
119
                $opt['session']['path'],
120
                $opt['session']['domain'],
121
                $https_session // https only?
122
            );
123
124
            // if site is requested by http no session data is visible, so set cookie as flag to redirect to https
125
            setcookie(
126
                $opt['session']['cookiename'] . 'https_session',
127
                $https_session,
128
                time() + 365 * 24 * 60 * 60,
129
                $opt['session']['path'],
130
                $opt['session']['domain'],
131
                0, // must be available for http
132
                1 // communication only, no js
133
            );
134
        }
135
    }
136
137
    public function debug()
138
    {
139
        print_r($this->values);
140
        exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method debug() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
141
    }
142
143
    public function close()
144
    {
145
        // TODO really nothing?
146
        // maybe destroy variables here
147
    }
148
}
149