2.2.1: Cookies


this screencast gives a very basic
introduction to the concept of cookies and how they’re used to track the
session with the user in Software as a Service, or SaaS. HTTP is a stateless protocol: every request to a SaaS app is
independent every other request. So if you want to
be able to identify the same user when they return to our site, or if you want to remember which page a
multi-page flow the user visited most recently, we have to somehow preserve that
information across HTTP requests. And that’s what cookies
allow us to do. To illustrate how they work I’ve created
an extremely simple app using the Sinatra framework, which is
much smaller than Rails. As we’ll see, in both Rails and Sinatra, sessions behave like a hash whose
contents are preserved across HTTP requests by the same user. In this screencast we’ll show how this machinery actually works. Don’t worry if you don’t understand this
tiny app exactly, and you can feel free to grab it from
GitHub to play with the app yourself, but the idea is that whenever a new user
visits the app’s homepage for the first time, a new empty session will be created, and
its count element will be initialized to the value 0.
Each time the pages visited again by that same user, the count will be increased by one. “erb” just tells Sinatra to wrap up its
argument in an HTML page that can be returned to the browser. The
other thing I have done in this app is I’ve added some code so that we can see the HTTP headers of both the request from the browser and
the response to the browser. The request headers will appear in blue
and the response headers will appear in red. So let’s start this app — you can see from
the messages in the console the app is listening on port 9292 — and we’ll open a Google Chrome Incognito window to visit the home page. Notice the HTTP response header “set-cookie”: This is the app telling the
browser to remember this string and pass it back
to the server the next time a request is made. The string may look like nonsense, but
it’s actually just encoded with a simple scheme called base64.
Looking at the browser we can see the number 1 is displayed,
wrapped in HTML. And if we reload the page there are two
things to notice. First, the request from the browser now includes a Cookie header, which
wasn’t there before. That’s because once the browser has
accepted a set-cookie header, it becomes the browser’s responsibility
to make sure that that cookie value is passed back to this app on future
requests. Second, this time the number 2 is
displayed in the browser window. That’s because our Sinatra app
correctly identified this request as being part of the same session, based on the information passed in the
cookie header. It retrieved the count value from the cookie, added 1, and stored the result back in
the cookie. That’s why we also see a set-cookie
header in the response to this request: that’s the app rewriting the value of
the cookie each time the session hash is updated. If we keep reloading you can see a
single character changing in the first chunk of the cookie value, but all of the characters changing in
the second chunk. This second chunk is like a fingerprint that matches the
rest of the cookie content, and if a malicious user tried to change
the cookie’s content, the app could detect that the
fingerprint didn’t match the value. The “session_secret” property of the app
provides the key for creating this fingerprint. So a malicious user would need to know
that key in order to pass off a doctored cookie as the real thing. We can also, as an experiment, use the
Chrome Developer Toolbar to disable cookies entirely. If we do
that, as you can see our app keeps trying to
use set-cookie in the response headers to rewrite the cookie value, but the
browser has stopped sending the cookie header with each new request. The result of this is that every request is now truly
independent and feels like the first request of a new session, so the number displayed in our webpage never changes. To summarize what we learned: many SaaS frameworks, including Sinatra and Rails, make it easy to store information in the
session. Each user gets their own session and by default the session information
is stored in cookies managed by that user’s browser. When
your app modifies the session information, the framework includes a set-cookie
header in the HTTP response, causing the browser to store the new
cookie value. When the browser passes back the cookie value with a cookie header in each request, the
framework can identify which session the cookie is associated with and retrieve the session information. Lastly, we saw that although the information in the cookie is not stored securely, it is protected by a fingerprint that
cannot be forged without each app’s secret session key, and this fingerprint
can be used to detect whether a malicious user has tampered
with the cookie.

2 Replies to “2.2.1: Cookies”

Leave a Reply

Your email address will not be published. Required fields are marked *