Misconfigured caching can lead to various vulnerabilities. For example, attackers may use badly-configured intermediate servers (reverse proxies, load balancers, or cache proxies) to gain access to sensitive data. Another way to exploit caching is through Web Cache Poisoning attacks.
The browser cache may look like a very safe place to temporarily store private information. The primary risk is that an attacker may gain access to it through the file system, which is usually considered a low-hazard vulnerability. However, in some cases, misconfigured cache-related headers may cause more serious security issues.
Cross-Domain Interaction Risks
Some websites have several subdomains and need to share data between them. This is normally not possible due to the same-origin policy (SOP). There are some methods that enable such cross-domain interaction, for example, JSONP (JSON with Padding). Developers who use such methods must implement some kind of protection against data leaking to other sites.
Let’s say that an example site has two subdomains: blog.example.com and account.example.com. The account.example.com site has a JSONP endpoint that returns sensitive user data on the basis of the user cookie. To prevent leaks, this endpoint verifies the
Referer header against a whitelist that includes blog.example.com.
With this setup, if the user is lured to visit a malicious site, the attacker cannot directly steal sensitive data. However, if the JSONP endpoint sets cache-related headers, the attacker may be able to access private information from the browser cache.
Browsers have slightly different cache implementations but certain aspects are similar. First of all, only GET responses may be cached. When the browser gets the response to its GET request, it checks response headers for caching information:
- If the response contains a
Cache-Control: publicheader, the response is cached for
- If the response contains an
Expiresheader, the response is cached according to its value (this header has less priority than
- If none of these headers is present, some browsers may check the
Last-Modifiedheader and typically cache the response for ten percent of the difference between the current date and the
- If there are no cache-related headers at all, the browser may cache the response but usually revalidates it before using it.
The Anatomy of the Attack
The following is a step-by-step explanation of how this vulnerability is used for an attack:
- The user visits blog.example.com.
- A script on blog.example.com needs user account information.
- The user’s browser sends a request to the JSONP endpoint at account.example.com.
- The response from the JSONP endpoint at account.example.com contains cache-related headers.
- The user’s browser caches the response content.
- The user is lured to a malicious site
- The malicious site contains a script that points to the JSONP endpoint at account.example.com.
- The browser returns the cached response to the script at the malicious site.
In this situation, the
Referer header is never checked because the response comes from the cache. Therefore, the attacker gains access to cached private information.
The same approach may be used to exploit other variations of Cross-Site Script Inclusion (XSSI) and other SOP Bypass attacks. Such attacks may bypass other server-side checks, for example, the
Origin header, the
SameSite cookie attribute, or custom headers.
Let us assume that account.example.com uses Cross-Origin Resource Sharing (CORS) instead of the JSONP endpoint. It returns an
Access-Control-Allow-Origin: * header but uses a special token from a custom header to authenticate the user and protect sensitive data.
If responses are cached, the attacker may steal private information by making a request to the same URI. There is no CORS protection (due to
Access-Control-Allow-Origin: *) and the user’s browser will return cached data without checking for the custom header token.
You can see how these vulnerabilities work in practice by analyzing the outputs of the browser console at a dedicated test site.
How To Protect Against SOP Bypass
The described SOP bypass vulnerability is caused by misconfiguration. In the case of cross-origin interactions, you should disable the browser cache. Most frameworks and ready-made scripts either don’t set cache-related headers or set them correctly by default (
Cache-Control: no-store). However, you should always double check these headers to be secure.
Browser vendors are now considering or implementing a stricter approach to caching. Hopefully, this change will prevent such cross-origin leaks.
Note – The tricks invented for the purposes of this article were inspired by the HTTP Cache Cross-Site Leaks article by Eduardo Vela.