krakjoe / apcu

APCu - APC User Cache
Other
958 stars 194 forks source link

NOT sharing APCu cache with php-fpm #238

Open freakyjoe8 opened 7 years ago

freakyjoe8 commented 7 years ago

Hi,

we installed apcu on a php-fpm based vhost environment. There is one daemon process running as root and several forks (pools) for every domain. Those pools are running under different usernames. While using apcu in this environment we realized that there is just one single apcu cache for all pools and all users. Is there any way to separate them so that every pool has its own cache?

Thanks!

martintamare commented 6 years ago

+1

TysonAndre commented 1 year ago

A workaround is to use whatever differs between pools as the prefix for APCu keys and access apcu through helper methods, e.g.

// Web server/application folder, possibly a symlink.
// Whether to include this depends on your deployment method.
$dir = realpath(__DIR__);
if (!$dir) {
   throw new Error('Failed to find real path of __DIR__');
}
$key = $dir . '/' . getmyuid();
define('APCU_PREFIX', substr(base64_encode(sha1($key, true)), 8) . '#');

function apcu_wrapper_fetch($key, $success = null) {
   return \apcu_fetch(\APCU_PREFIX . $key, $success);
}
// and so on
nxmndr commented 6 months ago

Quite the security issue. Too bad because I really like the idea of APCu.

Even though separating with a hashed key helps a bit, APCu being made to be fast makes it vulnerable to bruteforce. An option to force cache separation per vhost would be nice.

AgentOak commented 6 months ago

It's unfortunate that the APCu PHP API is all global functions, rather than methods on an object, which could require some sort of key in its constructor to access different cache instances.

But as it is, the better fix is correcting the fundamental design flaw of PHP-FPM sharing most of everything between completely unrelated workers. For example OPcache and many php.ini settings are also shared, which at the very least leaks file paths to other pools.

One can separate all caches by running a separate php-fpm master instance per pool, for example by making an instantiated/templated systemd service to run php-fpm (e.g. php-fpm@site-a.service and php-fpm@site-b.service) or by using containers.