How to defend against Account Takeovers
Learn about account takeover threats, protection strategies, and detection methods to secure your digital accounts and prevent unauthorised access.
Support FAQ
Cache-Control is an HTTP header that tells browsers and shared caches how they may store, reuse, and revalidate a response. It is one of the main ways an origin server communicates caching intent to downstream systems, including browser caches, proxy caches, and CDNs.
The header matters because caching is both a performance feature and a correctness boundary. A good Cache-Control policy can make static assets load quickly, reduce origin traffic, and improve resilience during spikes. A bad policy can serve stale information, hide deployment problems, overload the origin, or expose private data through a shared cache.
A response can be stored only when policy allows it. Once stored, it can be served without contacting the origin while it is fresh. Freshness is usually controlled by a lifetime such as max-age=3600, which means the response can be considered fresh for 3,600 seconds after it is generated. When that time passes, the cache may need to revalidate the response or fetch a new copy.
Cache-Control applies differently depending on the cache. A browser cache is tied to one user agent. A shared cache, such as a CDN, may serve many users. This distinction is critical. A response that is safe for a user's browser to store is not necessarily safe for a shared CDN cache to reuse across users.
max-age sets the freshness lifetime for caches that honor the response. For example, Cache-Control: max-age=600 permits reuse for ten minutes.
s-maxage sets a freshness lifetime for shared caches and overrides max-age for those caches. This allows a page to be cached briefly at a CDN while telling browsers to revalidate more often.
public explicitly marks a response as reusable by shared caches, assuming no other directive prevents it. It is often used for assets and pages that contain no user-specific data.
private tells shared caches not to store the response, while allowing a browser cache to store it for that user. This is useful for user-specific pages that can safely be kept locally but must not be reused for other people.
no-store tells caches not to store the response at all. It is appropriate for highly sensitive responses such as account data, payment flows, tokens, or pages where local storage would be unacceptable.
no-cache is commonly misunderstood. It does not mean "do not store." It means a stored response must be revalidated with the origin before reuse. If the origin confirms the response is still valid, the cache can use its stored copy.
stale-while-revalidate allows a cache to serve a stale response for a limited time while it refreshes the object in the background. stale-if-error allows stale serving when the origin returns an error or is unavailable. These directives can improve resilience, but only for content where temporary staleness is acceptable.
For versioned static assets, a long TTL is often safe:
Cache-Control: public, max-age=31536000, immutable
This fits files whose URL changes when the content changes, such as hashed JavaScript, CSS, font, or image filenames. It is risky for unversioned files that are overwritten in place.
For a public HTML page that changes regularly:
Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=30
This lets browsers treat the page as fresh briefly, allows shared caches to keep it longer, and gives the CDN a short window for background refresh. The exact durations depend on publishing expectations and the risk of stale content.
For user-specific account pages:
Cache-Control: private, no-cache
This allows storage only in the user's own cache and requires revalidation before reuse. For more sensitive routes, no-store may be the better choice.
For payment, token, or administrative responses:
Cache-Control: no-store
The point is not to copy these values everywhere. The point is to align the directive with the route's sensitivity, freshness needs, and cache key.
CDNs commonly honor Cache-Control, but they may also allow route rules, cache overrides, custom headers, origin shield behavior, purge APIs, and platform-specific cache settings. This can be useful when an application cannot emit ideal headers, but it can also hide intent. If the CDN caches a response despite confusing origin headers, the next operator may not understand why production behavior differs from code.
The cache key must be considered with Cache-Control. A response might be cacheable for ten minutes, but if it varies by cookie, language, device, query parameter, or authorization state, the cache must distinguish those variants correctly. Vary headers and CDN cache-key rules can either protect correctness or fragment the cache so heavily that the hit ratio collapses.
The most serious failure is caching private data in a shared cache. This can happen when personalized pages are marked public, when Set-Cookie behavior is ignored, when authorization headers are mishandled, or when the cache key omits a meaningful user-specific signal.
Another common failure is assuming no-cache prevents storage. If a route must not be stored, use no-store. Teams also get into trouble with long TTLs on unversioned assets, CDN overrides that conflict with application headers, broad full-site purges, and error responses that are cached longer than intended.
Attackers may exploit weak cache policy through cache poisoning, cache deception, or cache-busting. Poisoning attempts try to place a malicious or misleading response into cache. Cache deception attempts to make private content look like a cacheable static file. Cache-busting uses unique URLs or query strings to force misses and increase origin load. Sensible cache keys, route allowlists, input validation, and edge security controls reduce these risks.
Review policies by route, not by site-wide preference. For each route, ask whether the response is public or user-specific, whether it can be stored by a browser, whether it can be stored by a shared cache, how long it can remain fresh, what attributes change the response, and how updates are invalidated.
Then verify production behavior. Inspect headers with and without cookies or authentication. Check CDN cache status, browser caching behavior, origin logs, purge events, and route-level rules. Confirm that redirects, errors, and API responses have deliberate policy rather than inheriting accidental defaults.
The best Cache-Control configuration is boring to operate: static assets stay fast, public pages refresh within known bounds, private routes stay private, stale serving is intentional, and the logs explain why each important response was hit, missed, bypassed, or revalidated.
Learn about account takeover threats, protection strategies, and detection methods to secure your digital accounts and prevent unauthorised access.
An overview of Account Takeover Attacks
A practical reference for common AI crawler user agents, operators, purposes, and recommended Peakhour bot-management actions.
AI For Cybersecurity explains the concept in the context of AI security, with practical checks and mitigation considerations for site operators.
AI Image Generation explains the concept in the context of AI security, with practical checks and mitigation considerations for site operators.
AI Misuse explains the concept in the context of AI security, with practical checks and mitigation considerations for site operators.
© PEAKHOUR.IO PTY LTD 2026 ABN 76 619 930 826 All rights reserved.