Cache Controls Explained
Table of Contents
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.
Cache Controls
There are three cache controls relevant to a penetration test: Cache-Control
, Expires
, and Pragma
. These are the core controls to instruct web clients on how data should be cached.
1. Cache-Control
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.
2. Pragma
Pragma is a header for HTTP/1.0 clients that do not support HTTP/1.1. Pragma supports only one directive, no-cache
.
3. Expires
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:
C:\Users\[username]\AppData\Local\Google\Chrome\User Data\Default\Cache
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:
C:\Users\[username]\AppData\Local\Mozilla\Firefox\Profiles\pzgfedoh.default-release\cache2
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:
Cache Validation
Validation is a term used frequently when talking about cache controls and it’s especially important for penetration testers to understand. Directives like no-cache
and must-revalidate
tell a browser only to use a resource after using ETags
or Last-Modified
header to check for a newer version:
If-None-Match: "[etag]"
Conclusion
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.