Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.
/ worker-auth Public archive

To demonstrate and implement a PoC to protect your site against XSS & CSRF attacks

License

Notifications You must be signed in to change notification settings

ngshiheng/worker-auth

Repository files navigation

worker-auth

Context

To start, we need to stop comparing JWT and Cookie! They are not the same. Instead, the right comparison would be:

  1. Token-based authentication
  2. Session-based authentication

In this PoC, we will only talk about token-based authentication (specifically using JWT). You should check out the tradeoffs between using token-based authentication and session-based authentication.

When using token-based authentication, the most asked question is "where to store JWT in the browser?".

Generally, there are 2 common ways to store authentication tokens in the browser:

  1. Cookie - vulnerable to XSS attacks
  2. Local Storage - vulnerable to to CSRF/XSRF attacks

Motivation

The goal of this PoC is to demonstrate and implement a "modified" version of the "Cookie-to-header token" approach to protect your site against XSS & CSRF attack (credits: 100% Stateless with JWT) when storing authentication tokens in Cookie.

Some other CSRF protection approaches are:

Read more...

User Workflow

The "Classic" Approach

This is vulnerable to CSRF attacks because our jwt would be automatically sent by our browser (client) to the server.

sequenceDiagram
    autonumber
    actor Client
    participant Server

    Client->> Server: POST /login
    Note right of Server: sign <jwt>
    Server-->>-Client: 200 Logged in
    Note over Server,Client: Set-Cookie: <jwt>
    Note left of Client: stores <jwt> in cookie
    Client->> Server: POST /hello
    Note over Client,Server: Cookie: <jwt>
    Note right of Server: verify <jwt>
    Server-->>-Client: 200 OK
Loading

The Modified "Cookie-to-header token" Approach

While our jwt is automatically sent by our browser, the server requires the client to also send along a csrfToken for verification.

sequenceDiagram
    autonumber
    participant Local Storage
    actor Client
    participant Server

    Client->> Server: POST /login
    Note right of Server: sign <jwt> with generated <csrfToken> as claim
    Server-->>-Client: 200 Logged In
    Note over Server,Client: Set-Cookie: <jwt> & X-CSRF-Token: <csrfToken>
    Note left of Client: stores <jwt> in cookie
    Client-->>Local Storage: setItem("csrf-token", <csrfToken>);
    Local Storage->>Client: getItem("csrf-token");
    Client->> Server: POST /hello
    Note over Client,Server: Cookie: <jwt> & X-CSRF-Token: <csrfToken>
    Note right of Server: verify <jwt> & compare <jwt> <csrfToken> & X-CSRF-Token <csrfToken>
    Server-->>-Client: 200 OK
Loading

Tech Stack

Requirements

Setup

❯ npm ci
# ...omitted for brevity...

❯ wrangler login
# ...omitted for brevity...

❯ wrangler kv:namespace create "USERS"
# ...omitted for brevity...
Add the following to your configuration file in your kv_namespaces array:
{ binding = "USERS", id = "bd445a5887f6437cb4ec9adb11a19106" }

❯ wrangler secret put SALT
 # ...omitted for brevity...
✨ Success! Uploaded secret SALT

Usage

wrangler dev --remote

To test a CSRF attack, check out this little tool (credits: Shrikant).

Reference