In recent years it has become popular to use Content Delivery Networks (CDN) provided by cloud hosting providers. Amazon’s CloudFront is an example of a popular CDN. These CDNs can take advantage of HTTP Caching to reduce latency for a global pool of end users.

There have been several fascinating attacks that abuse this caching functionality. James Kettle’s Web Cache Poisoning attack allows an attacker to inject malicious responses into the web cache. Omer Gil’s Web Cache Deception illustrates a technique whereby an attacker can lure a legitimate user into visiting a bogus URL causing sensitive information, such CSRF tokens and cookies, to be saved in the cache for anyone to access.

Studying these attacks made me wonder what conditions might cause session cookies to get caught up in the cache to create a form of web cache session hijacking. Let’s find out.

A Simple Experiment

To test this theory the Amazon Flask Demo was slightly modified to add a random session cookie. This was done by adding the following response hook to the application:

SHOULD_CACHE = False

@application.after_request
def apply_uuid(response):
    response.set_cookie("session", str(uuid4()))

    if SHOULD_CACHE:
        response.cache_control.public = True
        response.cache_control.max_age = 31536000
    else:
        response.headers['Last-Modified'] = datetime.datetime.utcnow()
        response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, private, post-check=0, pre-check=0, max-age=0'
        response.headers['Pragma'] = 'no-cache'
        response.headers['Expires'] = '0'

    response.headers['Vary'] = 'cookie'

    return response

The application was deployed first with SHOULD_CACHE = False behind CloudFront with Cookie Forwarding enabled. As would be expected, a random session cookie was returned every time:

$ curl -s -i https://dcwlffg7doyym.cloudfront.net | grep -i Set-Cookie
set-cookie: session=7045f066-b5aa-4a0a-8084-ad249ae98be9; Path=/
$ curl -s -i https://dcwlffg7doyym.cloudfront.net | grep -i Set-Cookie
set-cookie: session=118da511-6938-4455-b7bd-fe2fb1fb1f6b; Path=/
$ curl -s -i https://dcwlffg7doyym.cloudfront.net | grep -i Set-Cookie
set-cookie: session=578d59f1-c8b8-4d4f-985e-44e781da426f; Path=/

Next the application was deployed with SHOULD_CACHE = True behind CloudFront with cookie forwarding enabled. At that point constant cached cookies began to be returned:

$ curl -s -i https://dcwlffg7doyym.cloudfront.net | grep -i Set-Cookie
set-cookie: session=8d8b0b49-d218-463b-a424-fe5b6e644c89; Path=/
$ curl -s -i https://dcwlffg7doyym.cloudfront.net | grep -i Set-Cookie
set-cookie: session=8d8b0b49-d218-463b-a424-fe5b6e644c89; Path=/
$ curl -s -i https://dcwlffg7doyym.cloudfront.net | grep -i Set-Cookie
set-cookie: session=8d8b0b49-d218-463b-a424-fe5b6e644c89; Path=/

This is a bit terrifying. A simple application misconfiguration causes session cookies to be leaked to unauthenticated users. Consider the impact of that. If an unauthenticated user in the same caching region happens to hit the site at the right moment, then they would all the sudden be logged in with an authenticated session.

Conclusion

This simple experiment showed that it is possible to leak session cookies in a poorly configured web application. The problem is a confluence of allowing the CDN to forward cookies and poor cache control responses in the application. In general, cached content should be limited to static resources on a site and the Set-Cookie header should never be issued for responses cached in the CDN.