Skip to content

Instantly share code, notes, and snippets.

@nrktkt
Last active August 21, 2020 23:48
Show Gist options
  • Save nrktkt/f3c43b60b700af39563c050b29a3dfb2 to your computer and use it in GitHub Desktop.
Save nrktkt/f3c43b60b700af39563c050b29a3dfb2 to your computer and use it in GitHub Desktop.
Securing websocket connections from browsers

Securing a websocket connection is a mess.

A good solution needs to

  1. work from the browser
  2. be hardened against CSRF
  3. be stateless
  4. work on IE 11 :(

To that end, the following should work:

  • assuming the user is already authenticated (and that the site doesn't already have CSRF or XSS vulnerabilities)
  1. make a "websocket preauth" request to the backend from js using the site's normal auth
  2. backend returns a CSRF token in the response body and sets a "websocket auth" cookie with SameSite=Strict in the response headers
  3. attempt to establish a websocket connection with the backend, with the addition of the CSRF token in a query parameter
  4. the backend checks
    • that the websocket auth cookie and CSRF token are valid
    • that the value of the Origin header matches an approved domain
  5. the backend sends a response and upgrades the connection to use websockets

Considerations

  • the websocket auth cookie MUST uniquely identify the user and include any authz scopes
  • the websocket auth cookie should be short lived (< 60s)
  • the CSRF should identify the websocket auth cookie
    • a JWT with a sub field with a value that identifies the websocket auth cookie would be a good choice
  • you should set the Secure attribute when setting the websocket auth cookie, but in theory it doesn't matter since the cookie can't be used without the CSRF token

Differences from general CSRF protection

Websockets don't

  • have SOP
  • allow headers to be set on the handshake request

therefore

  • the CSRF token needs to be put in a query parameter instead of a header
  • the Origin header needs to be checked explicitly, the backend can't assume that any CORS settings will take effect

also

  • the websocket auth cookie can be short-lived since the websocket can continue to be used after it expires
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment