How does Caching work?

All forms of Caching in computer science, whether it be CPU cache, HTTP Web Server cache, Database cache and so on, aims to speed up response times for whatever is requested. Doing so helps reduce load as much as possible on the component that is being actively cached.

Because of this principle, caches tend to sit between the client/user and the server/component. This is very important to understand, in order to understand Web Cache Poisoning. In the web’s ecosystem, the types of caches that are used can vary. Some examples include but are not limited to:

  • Memcached
  • Varnish
  • CDNs (i.e. Akamai, MaxCDN, AWS)

web cache poisoning

Moving on, any reference to cache is in the context of web application caching like the ones mentioned above.

The idea behind caching is very simple. Statically store “answers” (responses) to “questions” (requests) that are frequently requested—bypassing the need to re-compute heavy requests. A caching system needs to have at least two key functionalities in place:

  1. How long to cache an item (i.e. File, HTTP Request, etc.) for
  2. Determining whether or not a request hits the cache (therefore quick response) or misses it (therefore needs to ask the application)

We’re not too concerned about the 1st option. The 2nd option can be solved by using a key-value store which sounds simple, but is definitely tricky to implement. The issue here is deciding what gets put in the key to determine if its unique or not.

Example

Imagine we are a caching system for a simple site that always resides on the same domain example.com. In that case, using the endpoint as a key would be great:

Request

POST https://example.com/stats?page=1 HTTP/1.1
Host: example.com
Accept-Language: en-US

Response

HTTP/1.1 200 OK

<h1>Stats Page 1</h1>
<p>Language: en-US</p>

This means we can now cache that response for the next user requesting the path /stats?page=1:

Cache

Key Value
stats?page=1 Stats Page 1
Language: en-US

You may notice that the caching system will consider the following two requests to be the same. However the Accept-Language headers differ slightly.

Request 1

POST https://example.com/stats?page=1 HTTP/1.1
Host: example.com
Accept-Language: en-US

Request 2

POST https://example.com/stats?page=1 HTTP/1.1
Host: example.com
Accept-Language: de

This is a problem because:

  1. The website will respond in English (US) even if the client requests the content to be in German, resulting in a visual bug.
  2. An unkeyed input (Accept-Language) is reflected in the page.

So what would happen if we sent a request with a Cross-site Scripting payload instead like so:

POST https://example.com/stats?page=1&cachebust=1 HTTP/1.1
Host: example.com
Accept-Language: <script>alert(document.domain)</script>

And the cache is updated.

Key Value
stats?page=1&cachebust=1 <h1>Stats Page 1</h1>
<p>Language: <script>alert(document.domain)</script></p>

This means that any user that accesses the URL https://example.com/stats?page=1&cachebust=1 will return the cached value. This includes the malicious payload without the application realizing, thus exploiting the user’s browser.

Remediating Cache Poisoning attacks

Defending yourself against Cache Poisoning attacks can be quite tricky. Disabling caching entirely is one such way which is not feasible for most and understandably so. Some helpful methods however are to:

  • Heavily cache static response, such as *.js, *.css, *.png files, blog posts, landing pages or any page that is always identical.
  • Make sure you are not vulnerable to Cross-site Scripting attacks so that even in the event of such a vulnerability, the user’s browser can’t be exploited.
  • Understand and restrict where caching is done. Are you using frameworks that implement their own caching? If so you may want to disable that and handle caching at a singular point (e.g. CloudFlare).
  • Avoid using user inputs (i.e. HTTP Headers) to be used as the cache key.

Conclusion

Finally, while all of the above can seem very daunting, web application scanners such as Acunetix can detect Web Cache Poisoning as well as Cross-site Scripting with pinpoint accuracy.

This will drastically reduce the time taken to discover such vulnerabilities and thus help you fix them before attackers discover them.

SHARE THIS POST
THE AUTHOR
Acunetix

Acunetix developers and tech agents regularly contribute to the blog. All the Acunetix developers come with years of experience in the web security sphere.