Issues (2473)

Branch: master

Security Analysis    no vulnerabilities found

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.

mod/web_services/start.php (1 issue)

Severity

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
2
/**
3
 * Elgg web services API plugin
4
 */
5
6
elgg_register_event_handler('init', 'system', 'ws_init');
7
8
function ws_init() {
9
	$lib_dir = elgg_get_plugins_path() . "web_services/lib";
10
	elgg_register_library('elgg:ws', "$lib_dir/web_services.php");
11
	elgg_register_library('elgg:ws:api_user', "$lib_dir/api_user.php");
12
	elgg_register_library('elgg:ws:client', "$lib_dir/client.php");
13
	elgg_register_library('elgg:ws:tokens', "$lib_dir/tokens.php");
14
15
	elgg_load_library('elgg:ws:api_user');
16
	elgg_load_library('elgg:ws:tokens');
17
18
	elgg_register_page_handler('services', 'ws_page_handler');
19
20
	// Register a service handler for the default web services
21
	// The name rest is a misnomer as they are not RESTful
22
	elgg_ws_register_service_handler('rest', 'ws_rest_handler');
23
24
	// expose the list of api methods
25
	elgg_ws_expose_function("system.api.list", "list_all_apis", null,
26
		elgg_echo("system.api.list"), "GET", false, false);
27
28
	// The authentication token api
29
	elgg_ws_expose_function(
30
		"auth.gettoken",
31
		"auth_gettoken",
32
		array(
33
			'username' => array ('type' => 'string'),
34
			'password' => array ('type' => 'string'),
35
		),
36
		elgg_echo('auth.gettoken'),
37
		'POST',
38
		false,
39
		false
40
	);
41
42
	elgg_register_plugin_hook_handler('unit_test', 'system', 'ws_unit_test');
43
}
44
45
/**
46
 * Handle a web service request
47
 * 
48
 * Handles requests of format: http://site/services/api/handler/response_format/request
49
 * The first element after 'services/api/' is the service handler name as
50
 * registered by {@link register_service_handler()}.
51
 *
52
 * The remaining string is then passed to the {@link service_handler()}
53
 * which explodes by /, extracts the first element as the response format
54
 * (viewtype), and then passes the remaining array to the service handler
55
 * function registered by {@link register_service_handler()}.
56
 *
57
 * If a service handler isn't found, a 404 header is sent.
58
 * 
59
 * @param array $segments URL segments
60
 * @return bool
61
 */
62
function ws_page_handler($segments) {
63
	elgg_load_library('elgg:ws');
64
65
	if (!isset($segments[0]) || $segments[0] != 'api') {
66
		return false;
67
	}
68
	array_shift($segments);
69
70
	$handler = array_shift($segments);
71
	$request = implode('/', $segments);
72
73
	service_handler($handler, $request);
0 ignored issues
show
$request is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
74
75
	return true;
76
}
77
78
/**
79
 * A global array holding API methods.
80
 * The structure of this is
81
 * 	$API_METHODS = array (
82
 * 		$method => array (
83
 * 			"description" => "Some human readable description"
84
 * 			"function" = 'my_function_callback'
85
 * 			"parameters" = array (
86
 * 				"variable" = array ( // the order should be the same as the function callback
87
 * 					type => 'int' | 'bool' | 'float' | 'string'
88
 * 					required => true (default) | false
89
 *					default => value // optional
90
 * 				)
91
 * 			)
92
 * 			"call_method" = 'GET' | 'POST'
93
 * 			"require_api_auth" => true | false (default)
94
 * 			"require_user_auth" => true | false (default)
95
 * 		)
96
 *  )
97
 */
98
global $API_METHODS;
99
$API_METHODS = array();
100
101
/** Define a global array of errors */
102
global $ERRORS;
103
$ERRORS = array();
104
105
/**
106
 * Expose a function as a web service.
107
 *
108
 * Limitations: Currently cannot expose functions which expect objects.
109
 * It also cannot handle arrays of bools or arrays of arrays.
110
 * Also, input will be filtered to protect against XSS attacks through the web services.
111
 *
112
 * @param string $method            The api name to expose - for example "myapi.dosomething"
113
 * @param string $function          Your function callback.
114
 * @param array  $parameters        (optional) List of parameters in the same order as in
115
 *                                  your function. Default values may be set for parameters which
116
 *                                  allow REST api users flexibility in what parameters are passed.
117
 *                                  Generally, optional parameters should be after required
118
 *                                  parameters.
119
 *
120
 *                                  This array should be in the format
121
 *                                    "variable" = array (
122
 *                                  					type => 'int' | 'bool' | 'float' | 'string' | 'array'
123
 *                                  					required => true (default) | false
124
 *                                  					default => value (optional)
125
 *                                  	 )
126
 * @param string $description       (optional) human readable description of the function.
127
 * @param string $call_method       (optional) Define what http method must be used for
128
 *                                  this function. Default: GET
129
 * @param bool   $require_api_auth  (optional) (default is false) Does this method
130
 *                                  require API authorization? (example: API key)
131
 * @param bool   $require_user_auth (optional) (default is false) Does this method
132
 *                                  require user authorization?
133
 *
134
 * @return bool
135
 * @throws InvalidParameterException
136
 */
137
function elgg_ws_expose_function($method, $function, array $parameters = NULL, $description = "",
138
		$call_method = "GET", $require_api_auth = false, $require_user_auth = false) {
139
140
	global $API_METHODS;
141
142
	if (($method == "") || ($function == "")) {
143
		$msg = elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet');
144
		throw new InvalidParameterException($msg);
145
	}
146
147
	// does not check whether this method has already been exposed - good idea?
148
	$API_METHODS[$method] = array();
149
150
	$API_METHODS[$method]["description"] = $description;
151
152
	// does not check whether callable - done in execute_method()
153
	$API_METHODS[$method]["function"] = $function;
154
155
	if ($parameters != NULL) {
156 View Code Duplication
		if (!is_array($parameters)) {
157
			$msg = elgg_echo('InvalidParameterException:APIParametersArrayStructure', array($method));
158
			throw new InvalidParameterException($msg);
159
		}
160
161
		// catch common mistake of not setting up param array correctly
162
		$first = current($parameters);
163 View Code Duplication
		if (!is_array($first)) {
164
			$msg = elgg_echo('InvalidParameterException:APIParametersArrayStructure', array($method));
165
			throw new InvalidParameterException($msg);
166
		}
167
	}
168
169
	if ($parameters != NULL) {
170
		// ensure the required flag is set correctly in default case for each parameter
171
		foreach ($parameters as $key => $value) {
172
			// check if 'required' was specified - if not, make it true
173
			if (!array_key_exists('required', $value)) {
174
				$parameters[$key]['required'] = true;
175
			}
176
		}
177
178
		$API_METHODS[$method]["parameters"] = $parameters;
179
	}
180
181
	$call_method = strtoupper($call_method);
182
	switch ($call_method) {
183
		case 'POST' :
184
			$API_METHODS[$method]["call_method"] = 'POST';
185
			break;
186
		case 'GET' :
187
			$API_METHODS[$method]["call_method"] = 'GET';
188
			break;
189
		default :
190
			$msg = elgg_echo('InvalidParameterException:UnrecognisedHttpMethod',
191
			array($call_method, $method));
192
193
			throw new InvalidParameterException($msg);
194
	}
195
196
	$API_METHODS[$method]["require_api_auth"] = $require_api_auth;
197
198
	$API_METHODS[$method]["require_user_auth"] = $require_user_auth;
199
200
	return true;
201
}
202
203
/**
204
 * Unregister a web services method
205
 *
206
 * @param string $method The api name that was exposed
207
 * @return void
208
 */
209
function elgg_ws_unexpose_function($method) {
210
	global $API_METHODS;
211
212
	if (isset($API_METHODS[$method])) {
213
		unset($API_METHODS[$method]);
214
	}
215
}
216
217
/**
218
 * Simple api to return a list of all api's installed on the system.
219
 *
220
 * @return array
221
 * @access private
222
 */
223
function list_all_apis() {
224
	global $API_METHODS;
225
226
	// sort first
227
	ksort($API_METHODS);
228
229
	return $API_METHODS;
230
}
231
232
/**
233
 * Registers a web services handler
234
 *
235
 * @param string $handler  Web services type
236
 * @param string $function Your function name
237
 *
238
 * @return bool Depending on success
239
 */
240
function elgg_ws_register_service_handler($handler, $function) {
241
	global $CONFIG;
242
243
	if (!isset($CONFIG->servicehandler)) {
244
		$CONFIG->servicehandler = array();
245
	}
246
	if (is_callable($function, true)) {
247
		$CONFIG->servicehandler[$handler] = $function;
248
		return true;
249
	}
250
251
	return false;
252
}
253
254
/**
255
 * Remove a web service
256
 * To replace a web service handler, register the desired handler over the old on
257
 * with register_service_handler().
258
 *
259
 * @param string $handler web services type
260
 * @return void
261
 */
262
function elgg_ws_unregister_service_handler($handler) {
263
	global $CONFIG;
264
265
	if (isset($CONFIG->servicehandler, $CONFIG->servicehandler[$handler])) {
266
		unset($CONFIG->servicehandler[$handler]);
267
	}
268
}
269
270
/**
271
 * REST API handler
272
 *
273
 * @return void
274
 * @access private
275
 *
276
 * @throws SecurityException|APIException
277
 */
278
function ws_rest_handler() {
279
280
	$viewtype = elgg_get_viewtype();
281
282
	if (!elgg_view_exists('api/output', $viewtype)) {
283
		header("HTTP/1.0 400 Bad Request");
284
		header("Content-type: text/plain");
285
		echo "Missing view 'api/output' in viewtype '$viewtype'.";
286
		if (in_array($viewtype, ['xml', 'php'])) {
287
			echo "\nEnable the 'data_views' plugin to add this view.";
288
		}
289
		exit;
290
	}
291
292
	elgg_load_library('elgg:ws');
293
294
	// Register the error handler
295
	error_reporting(E_ALL);
296
	set_error_handler('_php_api_error_handler');
297
298
	// Register a default exception handler
299
	set_exception_handler('_php_api_exception_handler');
300
301
	// plugins should return true to control what API and user authentication handlers are registered
302
	if (elgg_trigger_plugin_hook('rest', 'init', null, false) == false) {
303
		// for testing from a web browser, you can use the session PAM
304
		// do not use for production sites!!
305
		//register_pam_handler('pam_auth_session');
306
307
		// user token can also be used for user authentication
308
		register_pam_handler('pam_auth_usertoken');
309
310
		// simple API key check
311
		register_pam_handler('api_auth_key', "sufficient", "api");
312
		// hmac
313
		register_pam_handler('api_auth_hmac', "sufficient", "api");
314
	}
315
316
	// Get parameter variables
317
	$method = get_input('method');
318
	$result = null;
319
320
	// this will throw an exception if authentication fails
321
	authenticate_method($method);
322
323
	$result = execute_method($method);
324
325
326
	if (!($result instanceof GenericResult)) {
327
		throw new APIException(elgg_echo('APIException:ApiResultUnknown'));
328
	}
329
330
	// Output the result
331
	echo elgg_view_page($method, elgg_view("api/output", array("result" => $result)));
332
}
333
334
/**
335
 * Unit tests for web services
336
 *
337
 * @param string $hook   unit_test
338
 * @param string $type   system
339
 * @param mixed  $value  Array of tests
340
 * @param mixed  $params Params
341
 *
342
 * @return array
343
 * @access private
344
 */
345
function ws_unit_test($hook, $type, $value, $params) {
346
	elgg_load_library('elgg:ws');
347
	elgg_load_library('elgg:ws:client');
348
	$value[] = dirname(__FILE__) . '/tests/ElggCoreWebServicesApiTest.php';
349
	return $value;
350
}
351