I want to secure my PHP installation. I can disable some functions, like system()
, exec()
etc using disable_functions
in php.ini. But I can forget to disable some dangerous functions. Is it possible to disable all functions, excluding the ones already used in my application?
-
1I don't think this is possible with standard PHP. – deviantfan May 05 '16 at 07:43
-
5+1 for wanting to use a whitelist rather than a blacklist. I wish more people thought like you :-) – Mike Ounsworth May 05 '16 at 07:50
-
How do you determine which functions aren't dangerous? – hspaans May 05 '16 at 09:17
-
hspaans, I want to minimize privileges of PHP scripts. So I am looking for a way to disable all PHP functions, which are not used by my application, not just several functions. – checkbox May 05 '16 at 09:38
-
Technically you could probably use get_defined_functions() to list all default functions. But that would generate a massive string obviously so I would only do it if you can't find a better solution – Crecket May 05 '16 at 11:16
-
1@Crecket PHP doesn't have that many functions. 1026 on my machine. You can easily put them all into the blacklist and then go through it and delete all of the entries of the functions you want to use without too much trouble. Actually, this would probably be faster than attempting to list all of the functions you want to use. – UTF-8 May 05 '16 at 12:24
-
"without too much trouble" ? That's only true if you're starting with a very accurate list of the functions used in your code - this is not as trivial as it sounds (in addition to parsing all the code, to capture the functions called directly, you also need to consider callbacks). BTW one should probably be ensuring unused extensions are not loaded (and not loadable via dl) – symcbean May 06 '16 at 09:59
2 Answers
To hook into @UTF-8's comment, using PHP_Parser
, you can fairly easily generate a list of default PHP functions not actually used by your application which you can then store in the disabled_functions
configuration option:
<?php
require 'vendor/autoload.php';
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\NodeVisitorAbstract;
use PhpParser\PrettyPrinter\Standard;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Function_;
class Collector extends NodeVisitorAbstract
{
public $functions = [];
public function leaveNode(Node $node)
{
if ($node instanceof PhpParser\Node\Expr\FuncCall)
$this->functions[] = (string) $node->name;
}
}
$sourcePath = __DIR__ . '/test/';
$files = new \CallbackFilterIterator(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($sourcePath),
\RecursiveIteratorIterator::SELF_FIRST
),
function($current, $key, $iterator) { return preg_match('~.php$~i', (string) $current) > 0; }
);
$nodeTraverser = new NodeTraverser();
$nodeTraverser->addVisitor($visitor = new Collector());
$parserFactory = new ParserFactory();
$parser = $parserFactory->create(ParserFactory::PREFER_PHP7);
foreach ($files as $file)
{
$stmts = $parser->parse(file_get_contents((string) $file));
$nodeTraverser->traverse($stmts);
}
$defined_functions = get_defined_functions();
$blocked_functions = array_diff($defined_functions['internal'], $visitor->functions);
echo 'disabled_functions = "', join(',', $blocked_functions), '"', PHP_EOL;
Something similar can be created for disable_classes
, just look for PhpParser\Node\Expr\New_
instead.
Some things to consider:
- Your first step should be to reduce the amount of modules your instance of PHP is loading.
- It's going to be annoying to manage this.
- You're going to have a bad time if you use anything dynamically.
- Having a large
disable_functions
setting may have a performance impact. You may want to consider using Suhosin's whitelist functionality as suggested by https://security.stackexchange.com/a/122471/242.
You can use Suhosin extension which allows you to whitelist functions that you want to allow.
See Suhosin's suhosin.executor.func.whitelist configuration option.
suhosin.executor.func.whitelist
Comma separated whitelist of functions that are allowed to be called. If the whitelist is empty the blacklist is evaluated, otherwise calling a function not in the whitelist will terminate the script and get logged.
Note: This setting deactivates suhosin.executor.func.blacklist.
Suhosin (pronounced 'su-ho-shin') is an advanced protection system for PHP installations. It was designed to protect servers and users from known and unknown flaws in PHP applications and the PHP core. Suhosin comes in two independent parts, that can be used separately or in combination. The first part is a small patch against the PHP core, that implements a few low-level protections against buffer overflows or format string vulnerabilities and the second part is a powerful PHP extension that implements numerous other protections.

- 944
- 1
- 10
- 22