Completed
Push — master ( ee79b5...34b090 )
by Stefan
04:54
created

input_validation.inc.php ➔ valid_integer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 6
rs 9.4285
1
<?php
2
3
/* * *********************************************************************************
4
 * (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia
5
 * License: see the LICENSE file in the root directory
6
 * ********************************************************************************* */
7
?>
8
<?php
9
10
require_once(dirname(dirname(dirname(dirname(__FILE__)))) . "/config/_config.php");
11
12
require_once 'Options.php';
13
require_once 'DBConnection.php';
14
15
// validation functions return HTML snippets. Ideally, should be called after
16
// HTML <head>, for beautiful output even in these error cases
17
18
function input_validation_error($customtext) {
19
    return "<p>" . _("Input validation error: ") . $customtext . "</p>";
20
}
21
22
function valid_Fed($input, $owner) {
23
    try {
24
        $temp = new Federation($input);
25
    } catch (Exception $fail) {
26
        echo input_validation_error(_("This Federation identifier is not accessible!"));
27
        exit(1);
28
    }
29
30
    foreach ($temp->listFederationAdmins() as $oneowner)
31
        if ($oneowner == $owner)
32
            return $temp;
33
    echo input_validation_error(_("This Federation identifier is not accessible!"));
34
    exit(1);
35
}
36
37
function valid_IdP($input, $owner = 0) {
38
    if (!is_numeric($input)) {
39
        echo input_validation_error(_("Value for IdP is not an integer!"));
40
        exit(1);
41
    }
42
    try {
43
        $temp = new IdP($input);
44
    } catch (Exception $fail) {
45
        echo input_validation_error(_("This IdP identifier is not accessible!"));
46
        exit(1);
47
    }
48
49
    if ($owner !== 0) { // check if the authenticated user is allowed to see this institution
50
        foreach ($temp->owner() as $oneowner)
51
            if ($oneowner['ID'] == $owner)
52
                return $temp;
53
        echo input_validation_error(_("This IdP identifier is not accessible!"));
54
        exit(1);
55
    }
56
    return $temp;
57
}
58
59
function valid_Profile($input, $idp_identifier = NULL) {
60
    if (!is_numeric($input)) {
61
        echo input_validation_error(_("Value for profile is not an integer!"));
62
        exit(1);
63
    }
64
    try {
65
        $temp = new Profile($input);
66
    } catch (Exception $fail) {
67
        echo input_validation_error(_("This profile is not accessible!"));
68
        exit(1);
69
    }
70
71
    if ($idp_identifier !== NULL && $temp->institution != $idp_identifier) {
72
        echo input_validation_error(_("This profile is not accessible!"));
73
        exit(1);
74
    }
75
    return $temp;
76
}
77
78
function valid_Device($input) {
79
    $devicelist = Devices::listDevices();
80
    if (!isset($devicelist[$input]))
81
        echo input_validation_error(_("This device does not exist!"));
82
    return $input;
83
}
84
85
function valid_string_db($input, $allow_whitspace = 0) {
86
    // always chop out invalid characters, and surrounding whitespace
87
    $retval = trim(iconv("UTF-8", "UTF-8//TRANSLIT", $input));
88
    // if some funny person wants to inject markup tags, remove them
89
    $retval = filter_var($retval, FILTER_SANITIZE_STRING, ["flags" => FILTER_FLAG_NO_ENCODE_QUOTES]);
90
    // unless explicitly wanted, take away intermediate disturbing whitespace
91
    // a simple "space" is NOT disturbing :-)
92
    if ($allow_whitspace === 0)
93
        $retval = preg_replace('/(\0|\r|\x0b|\t|\n)/', '', $retval);
94
    else // even if we allow whitespace, not pathological ones!
95
        $retval = preg_replace('/(\0|\r|\x0b)/', '', $retval);
96
97
    return $retval;
98
}
99
100
function valid_integer($input) {
101
    if (is_numeric($input)) {
102
        return $input;
103
    }
104
    return FALSE;
105
}
106
107
108
function valid_consortium_oi($input) {
109
    $shallow = valid_string_db($input);
110
    if (strlen($shallow) != 6 && strlen($shallow) != 10)
111
        return FALSE;
112
    if (!preg_match("/^[a-fA-F0-9]+$/", $shallow))
113
        return FALSE;
114
    return $shallow;
115
}
116
117
function valid_Realm($input) {
118
    // basic string checks
119
    $check = valid_string_db($input);
120
    // bark on invalid constructs
121 View Code Duplication
    if (preg_match("/@/", $check) == 1) {
0 ignored issues
show
Duplication introduced by
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...
122
        echo input_validation_error(_("Realm contains an @ sign!"));
123
        return FALSE;
124
    }
125 View Code Duplication
    if (preg_match("/^\./", $check) == 1) {
0 ignored issues
show
Duplication introduced by
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...
126
        echo input_validation_error(_("Realm begins with a . (dot)!"));
127
        return FALSE;
128
    }
129 View Code Duplication
    if (preg_match("/\.$/", $check) == 1) {
0 ignored issues
show
Duplication introduced by
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...
130
        echo input_validation_error(_("Realm ends with a . (dot)!"));
131
        return FALSE;
132
    }
133 View Code Duplication
    if (preg_match("/\./", $check) == 0) {
0 ignored issues
show
Duplication introduced by
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...
134
        echo input_validation_error(_("Realm does not contain at least one . (dot)!"));
135
        return FALSE;
136
    }
137 View Code Duplication
    if (preg_match("/ /", $check) == 1) {
0 ignored issues
show
Duplication introduced by
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...
138
        echo input_validation_error(_("Realm contains spaces!"));
139
        return FALSE;
140
    }
141
    return $check;
142
}
143
144 View Code Duplication
function valid_user($input) {
0 ignored issues
show
Duplication introduced by
This function 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...
145
    $retval = $input;
146
    if ($input != "" && !ctype_print($input)) {
147
        echo input_validation_error(_("The user identifier is not an ASCII string!"));
148
        exit(1);
149
    }
150
    return $retval;
151
}
152
153 View Code Duplication
function valid_token($input) {
0 ignored issues
show
Duplication introduced by
This function 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...
154
    $retval = $input;
155
    if ($input != "" && preg_match('/[^0-9a-fA-F]/', $input) != 0) {
156
        echo input_validation_error(_("Token is not a hexadecimal string!"));
157
        exit(1);
158
    }
159
    return $retval;
160
}
161
162
function valid_coordinate($input) {
163
    if (!is_numeric($input)) {
164
        echo input_validation_error(_("Coordinate is not a numeric value!"));
165
        exit(1);
166
    }
167
    // lat and lon are always in the range of [-180;+180]
168
    if ($input < -180 || $input > 180) {
169
        echo input_validation_error(_("Coordinate is out of bounds. Which planet are you from?"));
170
        exit(1);
171
    }
172
    return $input;
173
}
174
175
function valid_coord_serialized($input) {
176
    if (is_array(unserialize($input))) {
0 ignored issues
show
Security Object Injection introduced by
$input can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read from $_POST, and $optname is assigned in web/admin/inc/option_parse.inc.php on line 33
  1. Read from $_POST, and $optname is assigned
    in web/admin/inc/option_parse.inc.php on line 33
  2. $a is assigned
    in web/admin/inc/option_parse.inc.php on line 34
  3. $a["{$obj_id}-1"] is passed to valid_coord_serialized()
    in web/admin/inc/option_parse.inc.php on line 114
  2. Path: Read from $_POST, and $optvalue is assigned in web/admin/inc/option_parse.inc.php on line 36
  1. Read from $_POST, and $optvalue is assigned
    in web/admin/inc/option_parse.inc.php on line 36
  2. $a is assigned
    in web/admin/inc/option_parse.inc.php on line 37
  3. $a["{$obj_id}-1"] is passed to valid_coord_serialized()
    in web/admin/inc/option_parse.inc.php on line 114

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...
177
        $tentative = unserialize($input);
0 ignored issues
show
Security Object Injection introduced by
$input can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read from $_POST, and $optname is assigned in web/admin/inc/option_parse.inc.php on line 33
  1. Read from $_POST, and $optname is assigned
    in web/admin/inc/option_parse.inc.php on line 33
  2. $a is assigned
    in web/admin/inc/option_parse.inc.php on line 34
  3. $a["{$obj_id}-1"] is passed to valid_coord_serialized()
    in web/admin/inc/option_parse.inc.php on line 114
  2. Path: Read from $_POST, and $optvalue is assigned in web/admin/inc/option_parse.inc.php on line 36
  1. Read from $_POST, and $optvalue is assigned
    in web/admin/inc/option_parse.inc.php on line 36
  2. $a is assigned
    in web/admin/inc/option_parse.inc.php on line 37
  3. $a["{$obj_id}-1"] is passed to valid_coord_serialized()
    in web/admin/inc/option_parse.inc.php on line 114

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...
178
        if (isset($tentative['lon']) && isset($tentative['lat']) && valid_coordinate($tentative['lon']) && valid_coordinate($tentative['lat']))
179
            return $input;
180
    } else {
181
        echo input_validation_error(_("Wrong coordinate encoding!"));
182
        exit(1);
183
    }
184
}
185
186
function valid_multilang($content) {
187
    if (!is_array($content) || !isset($content["lang"]) || !isset($content["content"])) {
188
        echo input_validation_error(_("Invalid structure in multi-language attribute!"));
189
        exit(1);
190
    }
191
}
192
193
function valid_boolean($input) {
194
    if ($input != "on") {
195
        echo input_validation_error(_("Unknown state of boolean option!"));
196
        exit(1);
197
    } else
198
        return $input;
199
}
200
201
function valid_DB_reference($input) {
202
    $table = "";
0 ignored issues
show
Unused Code introduced by
$table is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
203
    $rowindex = "";
0 ignored issues
show
Unused Code introduced by
$rowindex is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
204
    $rowindexmatch = [];
205
206
    if (preg_match("/IdP/", $input)) {
207
        $table = "institution_option";
208
    } elseif (preg_match("/Profile/", $input)) {
209
        $table = "profile_option";
210
    } elseif (preg_match("/FED/", $input)) {
211
        $table = "federation_option";
212
    } else
213
        return FALSE;
214
    if (preg_match("/.*-([0-9]*)/", $input, $rowindexmatch)) {
215
        $rowindex = $rowindexmatch[1];
216
    } else
217
        return FALSE;
218
    return ["table" => $table, "rowindex" => $rowindex];
219
}
220
221
function valid_host($input) {
222
    // is it a valid IP address (IPv4 or IPv6)?
223
    if (filter_var($input, FILTER_VALIDATE_IP))
224
        return $input;
225
    // if not, it must be a host name. Use email validation by prefixing with a local part
226
    if (filter_var("stefan@" . $input, FILTER_VALIDATE_EMAIL))
227
        return $input;
228
    // if we get here, it's bogus
229
    return FALSE;
230
}