Search code examples
symfonycachingnoncewsse

Symfony + WSSE: Why is the nonce cache folder 20GB in size?


I am working on a Symfony 3.4 based projects which uses a WSSE authentication as described in the Symfony docs.

Each nonce is stored as separate file in the cache dir myProject/var/cache/prod/security/nonces. Probelm is, that this dir becomes very, very large in size. The project has been up and running and the nonces already use almost 20GB in disk space!

$ cd myProject/var/cache/prod/security/
$ du -sch *
19G    nonces
19G    total

This seems pretty much to me... I tried to figure out how many nonces are stored and used the following command to count the files:

$ cd myProject/var/cache/prod/security/nonces
$ find -maxdepth 1 -type f | wc -l
4697417

Even for 4.7 million files 19GB seems pretty much. Each file would need to have a size of roughly about 4KB. However, as far as I can tell each file has only 10B...

$ cd myProject/var/cache/prod/security/nonces
$ ls -lh
-rw-r----- 1 user nobody 10 Jul 25 16:46 'MWFiYWM5YjAiOTRyOWRmZA=='
-rw-r----- 1 user nobody 10 Jul  1 19:41 'MWFiYWNiYTflNTdhLGYwYQ=='
-rw-r----- 1 user nobody 10 Sep 29 11:05 'MWFiYWNkNzEjZfFlCjM0OQ=='
...

I know that there is a difference between file size and consumed diskspace. However, du also shows 10B of disk space:

$ du -sb --apparent-size MWFiYWNkNzEjZfFlCjM0OQ==
10

So, how can the files use 19G of disk space while each files only uses 10B? Am I missing something? Or did I not use the commands correctly?

Isn't there a better to store the nonces?

Of course I could delete the cache every now and then. However, this would make the nonces pretty much useless, wouldn't it?


Solution

  • Filesize

    du reports the size of disk space that is consumed. Disk space is allocated in blocks. So the minimal space a file can occupy is 1 block. In your case the block size of your filesystem seems to be 4kb. Therefore ~4.7 million files with a size of 10byte consume 4700000 * 4kb, thats arround 19gb.

    How long to store nonces

    Nonces are usually cached for a few minutes. The symfony cookbook you mentioned recommends a nonce ttl of 5 minutes. Here is an extract of that documentation

    class WsseProvider implements AuthenticationProviderInterface
    {
      protected function validateDigest($digest, $nonce, $created, $secret)
        {
            // Check created time is not in the future
            if (strtotime($created) > time()) {
                return false;
            }
    
            // Expire timestamp after 5 minutes
            if (time() - strtotime($created) > 300) {
                return false;
            }
    
            // Try to fetch the cache item from pool
            $cacheItem = $this->cachePool->getItem(md5($nonce));
    
            // Validate that the nonce is *not* in cache
            // if it is, this could be a replay attack
            if ($cacheItem->isHit()) {
                // In a real world application you should throw a custom
                // exception extending the AuthenticationException
                throw new AuthenticationException('Previously used nonce detected');
            }
    
            // Store the item in cache for 5 minutes
            $cacheItem->set(null)->expiresAfter(300);
            $this->cachePool->save($cacheItem);
    
            // Validate Secret
            $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true));
    
            return hash_equals($expected, $digest);
        }
    }
    

    The nonces are added to the cache-pool with a ttl of 5 minutes. Keeping the nonces longer than the time you consider the created field valid (five minutes in this example if (time() - strtotime($created) > 300)) doesn't add any extra security, because as soon as the creation date becomes outdated a replayed request can be rejected based on the created timestamp.