As with any web technology, using a CDN can create security vulnerabilities. Researchers have discovered a variety of ways to abuse CDNs and attack the web applications that are using them.
Fortunately, these attacks are well-understood. Proper security measures can mitigate the risks. Before discussing these security best practices, it’s helpful to understand how the attacks work.
CDNs cache data and content from the origin server, and provide it in response to incoming requests. (For more information on this, see What is CDN?) There are several ways to exploit this process, but most are complicated, and have a low possibility of success for the attacker.
However, one form of attack is more straightforward than the others. More importantly, it has a higher potential for success. It is known as Cache Poisoning.
This involves “poisoning” or polluting a CDN’s cache, so that it returns useless or even harmful content to clients. Poisoning can be used for delivering hostile payloads, e.g. via XSS (Cross-Site Scripting). Or it can be used for indirect attacks like DoS (Denial of Service).
This attack is done in two stages. First, attackers look for vulnerabilities in a web application by sending requests with unusual or malformed inputs. During this process, attackers usually request URLs that are artificial and unique. This ensures they are not receiving cached content from the CDN; instead, they can directly observe the web application’s response to the inputs.
For example, a request header could contain a X-Forwarded-Server or X-Forwarded-Host field with a malicious script as its value. A vulnerable web application will incorporate the script into its response.
Now the attacker has confirmed that cache poisoning is possible. The next step is to actually poison it. This requires sending malicious requests to genuine URLs (the ones targeted for the attack), immediately after the caches for those URLs have expired.
When cached content expires, the CDN stops serving it. The next time a client requests that URL, the request will be passed to the web application. Its response will be returned to the client, and will also be cached by the CDN, to be served to subsequent clients until the next expiration time occurs.
Therefore, if the attacker can send a hostile request immediately after the current cache expires, a corrupted response will be generated by the web application. This response will be cached by the CDN, and served to all subsequent clients until the cache expires.
How can an attacker know when the current cache expires? Sometimes this is very easy; sometimes responses include headers which specify (whether explicitly or implicitly) the time remaining until expiration.
However, if the responses do not contain this information, then poisoning the cache becomes much more difficult. The attacker needs to continually send hostile requests until a corrupted response is eventually received. But this activity is likely to be recognized as an attack; if so, it will be blocked before it has a chance to succeed.
Therefore, securing a web application against these attacks is a two-fold process. First, ensure that the web application does not return its request inputs in a way that attackers can exploit. Second, ensure that the CDN and/or web application do not expose expiration times and other information that an attacker needs in order to succeed.
Denial of Service
An attacker can poison a cache with content that is not overtly malicious, but that will still interfere with the intended use of the targeted web application.
For example, an attacker can send requests that trigger errors in the origin server. When the server returns errors, the error page is stored in the CDN’s cache. From then on, legitimate clients do not receive their requested content. Instead, the CDN serves them the cached content, which is the error page.
This is known as CPDoS (Cache Poisoning Denial of Service), because it prevents clients from obtaining the content that was requested.
CPDoS can be accomplished in three primary ways:
- HTTP Header Oversize
- HTTP Meta Character
- HTTP Method Override
The first technique uses a request with a larger header size than the web server will accept. (For example, Apache’s default limit is 8,190 bytes.) This will trigger an error message that is then cached by the CDN.
The second technique uses a request with malicious meta characters in the header. If the CDN forwards the request to the origin server, it will be recognized as hostile, and result in an error.
The third technique uses a request with an unsupported HTTP method (such as DELETE). Most web servers will accept only methods such as GET, POST, and so on. Therefore, the request with an unsupported method will be rejected, and the error message will be cached.
Securing a web application against CPDoS is straightforward. First, these attacks are found in only a few forms. Therefore, a good WAF will be able to detect and prevent them.
Second, just like the hostile payload attacks, CPDoS attacks must be timed so that a malicious request is sent right after the current cache expires. Thus, to make it difficult for CPDoS attacks to succeed, response headers should be scrubbed of all cache-expiration information.