It is indeed risky to leave that code as it stands.
I tried to find a character that could prematurely clip a string. But although I found no way to do that, this is not conclusive, and there could be other ways to tamper with function names. As PHP offers namespace syntax (using \
), that also could be exploited by creative users.
But there is no reason to take the risk and allow user input to contain characters that should not occur in function names. Function names must follow rules:
Function names follow the same rules as other labels in PHP. A valid function name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
So, you could make sure any argument that has a violating character is rejected (including the backslash in namespace syntax). Using the quoted regular expression you could do that as follows:
function isValidName($name) {
return preg_match("/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/", $name);
}
$func = $_GET['func'] . '_xyz123';
if(isValidName($func) && function_exists($func)){
$result = $func($_GET);
echo(json_encode($result));
}
An additional way to secure the application, is to define all functions that can be called this way as static methods of a class. Let's assume that class is called _xyz123, and your functions would not have this suffix, then the code could look like this, using method_exists:
$func = $_GET['func'];
if(isValidName($func) && method_exists('_xyz123', $func)){
Or you could define all those functions in a specific namespace, e.g. _xyz123, and do this:
if(isValidName($func) && function_exists('\\_xyz123\\$func')){