Cache Controls Explained
Cache controls have been a fixture on application penetration test reports for over 20 years. They control a balance between security and performance which is still frequently debated today.
On one hand, security standards recommend that no application data is cached or stored in local browser directories. On the other hand, performance improves as artifacts and data can be cached to avoid excessive requests.
Although ultimately a low risk in nearly all contexts, organizations must decide what levels of caching are acceptable for their applications.
Cache Controls and Vulnerability Risk
Let’s first review some scenarios where caching may pose risk:
- Sensitive data stored locally is exposed to others in shared workstation environments, or forensically recovered if a device is lost.
- A malicious actor gains temporary access to a user’s device. The cached data (even when it’s not sensitive) indicates the owner is a user of your application, and the actor can then further target the owner.
There are three cache controls relevant to a penetration test:
Pragma. These are the core controls to instruct web clients on how data should be cached.
Cache-Control has a number of directives which are frequently misunderstood.
no-cache is the most frequent offender, where despite it’s name, it does not prevent data being cached locally.
no-cache only forces validation of the cached content, so the browser may store the data, but must check for new versions when the page is requested again.
private is also frequently misused. The term ‘private’ here is only reserved for “shared caches” such as proxies and does not apply to the end user.
private does not prevent any caching by web browsers.
no-store is the strongest and preferred directive for secure applications.
no-store instructs browsers not to store the content locally and is the only necessary directive.
Pragma is a header for HTTP/1.0 clients that do not support HTTP/1.1. Pragma supports only one directive,
Expires instructs the client how long to retain the content.
Expires is also identical to the
max-age directive of the
Cache-Control header and is ignored when
max-age is used.
Viewing Cached Data
For penetration testers needing a proof of concept for cached data, Chrome and FireFox browsers no longer store cached pages in readable files. If you absolutely need to view these files, NirSoft has a Chrome and FireFox viewer.
Chrome Cache Location
Chrome browsers currently store caches in the following path:
FireFox Cache Location
FireFox users can view their cache location by accessing
about:cache. The latest version of FireFox will show something similar to the following:
If you are looking to analyze performance tradeoffs between different configurations, it may be helpful to use a browser debugger (
F12 -> Network) to compare load times:
Validation is a term used frequently when talking about cache controls and it’s especially important for penetration testers to understand. Directives like
must-revalidate tell a browser only to use a resource after using
Last-Modified header to check for a newer version:
So what Cache Control headers do you need? For secure applications, we generally recommend the following headers:
Cache-Control: no-store Pragma: no-cache Expires: -1
Cache controls are defined in RFC 7234, but are not always properly implemented across web clients.
An application penetration test should attempt to reconcile this specification with known behaviors of commonly used browsers. Mitigation steps for this vulnerability should also consider performance requirements and ultimately defer to the business on resolution.