The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Security
What is a session, and where is the logged-in state remembered?
A session is a memory that is written in a store inside the server. In the code box, session is an argument of the type HttpSession, and it points to one slot in the server's session store that belongs to this request. The line session.setAttribute("user", "kim") in the login method writes "the user of this session is kim" in that slot, and the line session.getAttribute("user") in the me method reads that value from the slot. Each slot has a number the server gave it (the session ID), and the server gives only this number to the browser, as a cookie named JSESSIONID. The browser sends that cookie with every following request, and the server finds the slot in the store by the number and knows who it is. In this lab you change how /me is requested after logging in (without the cookie, by another person, after the server deleted the slot) and see whether the server recognizes who it is. The code box shows only the part that runs when login succeeds. The process of checking the username and password is not covered in this lab, so it was left out. What a cookie is follows the earlier "Cookies" lab.
Checked against real execution · Started Spring Boot 4.1.1 (embedded Tomcat 11.0.24) with real component scanning for 8 combinations, sent requests, and checked them (the HttpClient writes the Cookie header itself, and it was not run in a real browser)
@PostMapping("/login")
public String login(HttpSession session) {
// Write "the user of this session is kim" in the server's session store
session.setAttribute("user", "kim");
return "Logged in";
}
@GetMapping("/me")
public String me(HttpSession session) {
// Use the session ID in the request to find the slot in the store and read it
Object user = session.getAttribute("user");
return user == null ? "Unknown user" : "Hello, " + user;
}
These are the results of running Spring Boot 4.1.1 (Spring Framework 7.0.9, embedded Tomcat 11.0.24) on JDK 21. For all eight combinations, we compiled the same source as the code on the screen (with only the logout method, which is not on the screen, added) in the package app, started a new Java process together with a start class (@SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan), and checked. We did not register the controller by hand but let Spring scan for the classes, and we sent the requests over real HTTP after the server was up. We did not put Spring Security, JPA, or H2 on the classpath (because with Security present, requests could be blocked and session handling could differ). The code on the screen leaves out the package and import lines, the class declaration, and the logout method. The logout method runs session.invalidate() and returns "Logged out", and the process of checking the username and password is also left out because this lab does not cover it. What we checked against was the server's session store right after login (the number of sessions in the Tomcat session manager and what is written in each slot), the Set-Cookie of the login response, and the response to /me. "The same browser" is one client that writes the value of the Set-Cookie it received directly into the Cookie header of the next request (we did not use a cookie jar, and we did not run it in a real browser), "another person" is a separate connection (a separate client) that writes the same value into the Cookie header and sends it, and the server deleting the session was reproduced by first sending POST /logout with the same cookie. The IDs on the screen (3A9F…, B71E…) are made-up examples for explanation, and in reality they were 32 uppercase letters and digits that differed every run. What the documents decide is Chapter 7 of the Jakarta Servlet 6.1 specification (7.1.1: the standard name of the session tracking cookie is JSESSIONID, 7.2: a session is new until the client returns the tracking information to the server and joins it, and the id can be read with getId(), 7.5: once invalidation starts, new requests cannot see that session) and the API documentation of HttpSession (a session is a way to identify a user across more than one request and to store information about that user, and the identifier returned by getId is assigned by the servlet container and is implementation dependent). What follows is not decided by the documents but is behavior we observed in this version. The ID is 32 uppercase letters and digits and the cookie value does not contain kim; the cookie carries the attributes Path=/ and HttpOnly; a method that takes a session argument creates a session even if it does not call setAttribute, and a cookie goes out (Spring calls getSession() of the request to fill that argument; we confirmed this call in the bytecode of the Spring class); if /me is requested without a cookie, the server creates a new empty session and gives a new ID; even if the same ID is sent over a separate connection, the server treats it as the same session and does not create a new one (the connection ports of the two requests were different); if a request comes with the ID of a session the server deleted, the server creates a new session and gives a new ID; and the logout response has no Set-Cookie line that tells the browser to delete the cookie. The attack that steals a session ID and the defenses against it (session fixation, the HttpOnly setting, and so on) are not covered in this lab, and are left to the study labs ("Sessions and JWT" and "Session hijacking and session fixation"). We also did not cover the session timeout, how to share sessions among several servers, or methods that do not use cookies (such as putting the ID in the URL).
Previous lab: Authentication and authorization · Next lab: Tokens
Struck-through text was removed from the first version of the code; highlighted text was added.