Monday, March 24, 2025

Bulletproof Sessions: Secure Session Handling Without Cookies

 As if there weren't enough session handling mechanisms (session id's in each URL, cookies, http only cookies, JWT tokens in the request header), let me introduce you a novel one: having a service worker that intercepts and cryptographically signs all the requests to the origin.

With the traditional session handling mechanisms, we have a static piece of information, usually generated on the server, which gets sent back to the server with each request.

With the bulletproof sessions concept, the information sent back to the server is dynamic and can not be replayed or faked by an attacker.

Here's a sequence diagram of how it works




Per-request signing provides significant benefits over cookie-based session handling, including stronger security (CSRF protection, request integrity, and non-repudiation), greater flexibility across domains, support for decentralized identity, and fine-grained access control, among others.

Here's the public repo of a proof of concept I built in nodejs for the bulletproof sessions idea.

The bulletproof sessions concept offers the possibility to create some very innovative applications, has the potential to simplify the whole authentication with 3rd parties space, all while offering an increase level of security for these applications.

1. Security Benefits
Session Replay attacks
  • Cookie-Based Sessions
    • Vulnerability: Cookies are sent automatically with every request to the origin. If an attacker intercepts a session cookie (e.g., via a man-in-the-middle attack on an insecure connection), they can replay it to impersonate the user.
    • Danger Level: High without mitigations. Even with HTTPS, a stolen cookie from a compromised client (e.g., via XSS or malware) can be reused until it expires or is invalidated server-side.
    • Mitigations: Short-lived cookies, Secure and HttpOnly flags, and CSRF tokens reduce (but don’t eliminate) the risk.
    Token-Based Sessions (e.g., JWT)
    • Vulnerability: Tokens stored in localStorage or sent in headers can be intercepted (e.g., via XSS or network sniffing if not over HTTPS). If the token has a long expiry, it’s replayable until it’s revoked or expires.
    • Danger Level: High if tokens are long-lived or not properly secured. Revocation requires server-side blacklisting, which isn’t always implemented.
    • Mitigations: Short expiration times, refresh tokens, and HTTPS help, but stolen tokens remain usable until expiry.
  • Bulletproof sessions:
    Per-request signing with asymmetric cryptography (as discussed earlier) can significantly reduce the danger of replay attacks, offering a key advantage over cookies and tokens:
    • Request-Specific Data: Each request can include a unique element—like a timestamp, nonce, or request payload—in the signed data. The server checks this, rejecting any request that reuses an old signature.
      Server verifies the signature and ensures the timestamp is recent (e.g., within 5 seconds). A replayed request with an old timestamp fails.
    • Danger Level: Very low. Replay attacks become impractical because each signature is single-use and time-bound.
XSS (Cross-Site Scripting) Protection
  • Cookies: When set with the HttpOnly flag, cookies are inaccessible to JavaScript, reducing the risk of theft via XSS. However, an attacker can still make requests on behalf of the user if they hijack the page.
  • Tokens: Tokens stored in localStorage or sessionStorage are vulnerable to XSS because malicious scripts can access and steal them.
  • Bulletproof sessions: The private key is stored in the service worker’s isolated context or IndexedDB, making it harder for malicious scripts to access directly. However, if an attacker can interact with the service worker (e.g., via postMessage), they might trick it into signing malicious requests. While this offers a slight edge over tokens in localStorage, it’s not completely immune to XSS.
CSRF (Cross-Site Request Forgery) Protection
  • Cookies: Vulnerable to CSRF unless mitigated with additional measures like CSRF tokens, as cookies are sent automatically with requests.
  • Tokens: Generally less vulnerable because tokens aren’t sent automatically like cookies. However, if a system auto-attaches tokens to requests, CSRF risks could return.
  • Bulletproof sessions: If the signature includes request-specific data (e.g., a timestamp, nonce, or request body), the server can reject invalid or replayed signatures. This provides inherent CSRF protection, which is a clear advantage over traditional cookies.
CORS (Cross-Origin Resource Sharing) Flexibility
  • Cookies: Tricky for cross-origin requests. They require specific CORS headers (Access-Control-Allow-Credentials: true) and are often restricted, making cross-origin use cumbersome.
  • Tokens: Easier to manage with CORS, as tokens can be included in headers and controlled precisely.
  • Bulletproof sessions: Like token-based methods, the signature is added to a header, offering flexibility for cross-origin requests. The service worker can decide which requests to sign, potentially simplifying CORS scenarios compared to cookies.

2. Integration with Third-Party Identity Providers
  • Cookies: Tied to a single origin, so integrating with third-party identity providers (e.g., OAuth) often involves redirects or additional mechanisms, which can be complex.
  • Tokens: Well-suited for third-party integrations. Tokens like those from OAuth 2.0 can be obtained and used across origins seamlessly.
  • Bulletproof sessions: Potentially flexible, as the service worker could handle keys or tokens from third-party providers and sign requests accordingly.
Does It Bring Benefits?
Yes, but the benefits come with trade-offs:
  • Advantages:
    • Session Replay Protection: Request-specific signatures over the payload with a timestamp or nonce included makes this attack virtually impossible.
    • Stronger CSRF Protection: Request-specific signatures could eliminate the need for separate CSRF tokens.
    • CORS Flexibility: Similar to tokens, it simplifies cross-origin request handling compared to cookies.
    • Slight XSS Improvement: Isolating the private key in the service worker may reduce exposure compared to tokens in localStorage, though it’s not foolproof.
  • Drawbacks:
    • Performance Cost: Signing requests is slower than traditional methods.
    • Increased Complexity: Key management and implementation can be more challenging.
    • Third-Party Integration: Less straightforward than token-based methods, potentially requiring custom workflows.