Remembering State in HTTP
By default HTTP is stateless (it has no memory of what has happened before). This means that every interaction with the server is treated as an individual, new occurrence. This can be a a good thing: it greatly simplifies server design and resource requirements, and it's also hard or impossible to get a stateless service stuck in a bad state.
However, the stateless design is not without problems: as each interaction is treated as a separate occurrence there is no way that the server could know if two (or more) requests came from the same browser.
Sessions
Sessions are one mechanism that allow some form of state to be retained between connections to server. In the web context, a session is some form of data structure that can be used to store temporary data about how the user is interacting with the application. For example, you could store a user's name (or unique id) in the session, so you don't have to query the database each time you need it.
Sessions on the Server Side
While the exact mechanism used to maintain session data will differ between applications (for example using temporary files, databases, or internal memory) the core concept remains the same.
I like to think of sessions as a simple hash table data structure (or python dictionary). Each session is assigned a unique session id, which is then used as a key to retrieve any other data that is stored about the session.
Sticking with the python dictionary analogy session data could look like this:
#Key # Data
4242aab : { "userId": 42,
"userName": "Dan"
"permissions": "Admin"
}
4242aac : { "userId" : 24,
"userName" : "James",
"permissions : "user"
So each user has a unique session ID that relates to a record in the session object. Each user should only be able to access their own information, and there will be a row in the data structure for each user connected to the server.
We also need a way of linking a particular request to a user. There are several ways of maintaining this information, each usually relies on passing some token to the browser, that is then resubmitted during any requests made. The token itself usually contains the session ID and therefore can be used to identify who is making the request. The token itself may differ between applications, (for example using web storage or indexed db) but is generally a Cookie.
Session Timeline
- The User visits a web page and logs in to the site. The server will validate the user's credentials and create a new session object containing the authorised users ID. The sessionid for this object is returned to the client.
- The client stores the session id (usually in a cookie), and passes it to the server with any future requests.
- When the server receives a request with a session id attached, it looks it up in the session datastore and makes the information stored available for any further processing that takes place.
- When the client logs out, the information in the session datastore is removed.
Cookies
The next problem we need to overcome is how to send the unique session Id between the client and server.
Cookies are one approach to token management. Cookies can be stored on the client's machine by the server, then passed back to the server when requests are made. This allows the server to track each session though the cookie data.
Note
There are other ways of maintaining state. These take advantage of the way requests work:
-
Modify the URL and append the token (it becomes a parameter of the GET request)
-
Store state in 'hidden' form fields
Both work, but can be error prone (as they rely on the person implementing them to do a good job, rather than 'well developed' session management libraries).
Cookie Parameters
Cookies are set (or stored) on the client machine using the Set-Cookie HTTP Header.
Set-Cookie: <Cookie-Name>=<Cookie-Value>
The Cookie-Name field, sets the name of the cookie that is stored by the
browser, for example when using PHP based sessions the cookie will be
called PHPSESSID
The Cookie-Value field defines the data stored in the cookie. In the case of a PHP based session, this will be the unique identifier representing the session on the server.
Other General Cookie Options
There are several other options that can be set as part of a cookie:
Options can be set as part of the Set-Cookie
response, using
name=value pairs separated by semicolons.
-
Domain
indicates the Domain for which the cookie can be sent. By default
domain
will be set to the hostname of the page sending the cookie. NOTE: Sub-domains can be included in this value. So settingdomain: coventry.ac.uk
will transfer the cookie for cumoodle.coventry.ac.uk, mail.coventy.ac.uk etc.Additionally, the domain must be part of the hostname for the site setting the Cookie. So coventry.ac.uk cannot set
domain: google.com
. The security reasons for this are obvious. -
Path
provides us with another way to control when cookies will be sent to the server. If the
path
option exists in the URL that is requested, then the cookie is transmitted.Again, this relies on the domain being set, but it gives us some fine control over which cookies are transmitted to the site. For example, if we want to include a tracking cookie for only the store part of our website (/evil.org/store/*) we can set the path to be /store.
-
Expires
controls the lifespan of a cookie. Without expires being set, the cookie is valid only for a single session (until the browser is shut down).
Security Specific Options
There are also a couple of Security specific options for cookies which you should be aware of:
-
secure
is a flag that can be appended to the Set-Cookie header. When set, the cookie will only be transmitted over HTTPS.
-
HttpOnly
Another Flag that instructs the browsers that the cookie should not be accessible via JavaScript.
Note
While we like to deride Microsoft and the security of Internet Explorer, the HttpOnly flag was their idea, and was first introduced in IE6.
However, with the exception of Microsoft!, browser support for this is still patchy, and there are a few workarounds in the wild. For an interesting discussion see: https://www.owasp.org/index.php/HttpOnly#Browsers_Supporting_HTTPOnly
Depending on the framework, these may or may not be turned on by default. Thus we can make use of packet sniffing, or XSS to nab cookies and profit (more on that when we talk about XSS).
Manipulating Cookies
Several tools exist for modifying cookies (cURL, cookie inspector/modifier in chrome) -- you should find one that works for you. This can also be done using the JavaScript Console in the web browser. We can view and modify the contents of the current pages cookies in the browser's web console.
Evidently, we cannot do this with cookies that have the HttpOnly flag set.
Cookies for the current page can be read using:
document.cookie
Cookies can be set using:
document.cookie="<key>=<value>"
As well as directly editing the cookies in the console. We can also use the Network section of the developers toolbar to examine (and depending on the HTTP-ONLY sessions, modify) the cookie values.
Cookies and Sessions
Sessions are a common way to store per-user data during a set of interactions with a server. This allows us to work around the connection-less nature of HTTP.
Sessions are created by the PHP page, and can have variables set or unset during the lifetime of the session.
PHP (and other systems) keep track of sessions using Cookies. A unique identifier is stored on the browser as a cookie and transmitted as part of all requests. When a request is made, the unique identifier in the session cookie is mapped to the relevant set of user parameters stored in the servers memory.
Note
Note that sessions should only last for a single browsing session (ie until the browser is closed, or the cookie expires).
To store data permanently we need to use databases.
Important
While more permanent session cookies can seem like a good idea, as it stops a user having to log in each time they visit a site It is worth sassing expiry date (to get the user to periodically log back in). We will see what can be done with a session cookie in the session on XSS
In PHP the session is stored in the PHPSESSID
cookie.
Like any other cookie we can inspect the value in the browser:
document.cookie
"PHPSESSID=c18b3494fe3227a1b6a18d6652db6ad5"
Session Hijacking
While we can't directly modify the session parameters stored on the server (unless we can control the page where these setting are made) it may be possible to take control of another user's session. If we can snarf the ID token through the cookie (though XSS, Sniffing etc) then we can set our own session ID cookie to use this value.
Note
While the examples here are for PHP, the principle is the same for other
common web technologies.
For example: ASP.net stores it session IDS in the cookie
ASP.NET_SessionId
In summary
HTTP is a stateless protocol. However, for the modern, interactive web we need some way of remembering who is using the site. In this step we discussed HTTP sessions, and how they can be used to keep track of a users interactions with a server.
PHP and other dynamic languages make use of Sessions to identify unique users. The session ID is stored in a cookie, and transmitted to the server with each request. This gives the possibly for a security flaw, as if we can obtain another users session token, we will be identified by them on the server. We will discuss Session hijacking in more detail in the XSS tasks.