Skip to content

"Hard-Invalidation" required for UserContextInvalidator::invalidateContext() #593

Open
@das-peter

Description

@das-peter

The standard UserContextInvalidator::invalidateContext() might be prone to short-term information disclosure issues if used in a Varnish xkey-softpurge setup with hash caching enabled (hash_cache_ttl).
This because even after the invalidation the deprecated context will be returned for the next request before it will be updated in the varnish cache.
So while a logout / user switch will invalidate the context, the context hash will serve the invalidated context once more before it is updated. This could be abused to fetch information only available for the user with the "invalidated" context.

In my current project I've worked around this by hacking together a hard-purge version:

        if ($this->cacheProxyClient instanceof Varnish) {
            $instanceReflection = new \ReflectionObject($this->cacheProxyClient);
            $optionsProperty = $instanceReflection->getProperty('options');
            $optionsProperty->setAccessible(true);
            $optionsBackup = $invalidatorOptions = $optionsProperty->getValue($this->cacheProxyClient);
            if (stripos($optionsBackup['tags_header'] ?? '', 'xkey') !== false) {
                $invalidatorOptions['tags_header'] = 'xkey-purge';
                $optionsProperty->setValue($this->cacheProxyClient, $invalidatorOptions);
            }
        }
        try {
            $this->invalidator->invalidateContext($sessionId);
        } finally {
            if (isset($optionsProperty) && isset($optionsBackup)) {
                $optionsProperty->setValue($this->cacheProxyClient, $optionsBackup);
            }
        }

This ensures that the tags_header is set to xkey-purge for invalidation if xkey is used.

This is a pretty smelly approach and makes me think we might should have a general approach for soft- / hard-invalidations. Or at least a way to change tags_header at runtime rather than in config only.
I'm more tempted by a general approach because I use the above hack not only for context invalidation but also for cache items that have to be purged immediately - e.g. generic content pages vs. "real-time" info.

Before I start fiddling with code - any objections / ideas?

My current proposal would be to introduce a second parameter to TagCapable::invalidateTags to indicate the type of invalidation (default , hard, soft).
Caches that implement soft / hard-purge then can switch between these modes regardless of the configured default mode.
E.g. ProxyClient\Varnish::invalidateByPurgekeys() could toggle between the appropriate tags_header setting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions