0

Goal

  1. Authenticate the Client via HTTP Request.
  2. Authenticate the Client's WebSocket connection.
  3. Prevent exploitation of WebSocket connection(when a XSS Vulnerability is present on website).

How I'm doing this

Step 1 Client visits the website by making a regular HTTP request. Cookies are used to authenticate the Client and server responds with a JS snippet + AuthToken(Generated & Saved at Server):

(function() {
    var ws = new WebSocket("wss://localhost:1000");
    // application logic goes here
})();

Step 2 Server marks newly created WebSocket connection as Unsafe/Unknown. Client has to send AuthToken via that Connection. Server will mark the Connection safe once it receive as valid AuthToken from any active WebSocket connection.

Overview of both steps

Picture

Things I'm enforcing

  • AuthToken is short-lived(Expirable & One-time).
  • Encrypted transport, using WSS protocol
  • Origin is checked by the server header during WS handshake(To prevent CSWSH).
  • Server will process only messages that are sent over Safe marked connections.

Assumptions in the case of XSS Vulnerability

  1. WebSocket object ws(created in the start) cannot be tampered with.
  2. Attacker cannot create an Authenticated connection without Cookies.

I want to know if above system is reasonably secure against XSS?

litz
  • 3
  • 1

1 Answers1

1

No, unfortunately this isn't hard to overcome. There is very nearly nothing that can be done be legitimate script but not by XSS. The only exception is that, for some kinds of XSS / in some situations, the legit script might be guaranteed to run first (a significant advantage in adversarial code, though most legit scripts aren't built to take advantage of it). Depending on the situation, it also might not be safe for the malicious script to navigate the page, though this can be mimicked/spoofed in various ways.

Assuming that an attacker has carried out an XSS attack on an authenticated user of the site, the attacker then injects a script that does the following:

  1. Make a fetch/XHR call to the server, which is sent with cookies, to retrieve the auth code.
  2. Open a new WSS connection to the server, initially untrusted as usual.
  3. Transmit the new auth code from step #1, switching the connection from #2 to trusted.
  4. Transmit arbitrary commands along the now-trusted connection.

Alternatively, the attacker could instead simply modify the WebSocket.prototype object, monkey patching it so that (for example) any attempt to call send on any WebSocket will instead call an attacker-defined function that wraps the original WebSocket.prototype.send, letting the attacker view the sent message and modify or block it if desired. The wrapper also exposes the previously-hidden websocket object (via this in the wrapper function) so that the attacker can do things like add their own event handler for messages, letting the attacker see the responses of each message. This method can be prevented (by prepared code) using the freeze function to prevent modification of the object, but that requires the legitimate script running before the XSS-injected script.

CBHacking
  • 40,303
  • 3
  • 74
  • 98
  • I also thought of a weird design change where JS snippet deletes all the Cookies every time it ran and any arbitrary code that follows the original snippet fails to find Cookies. In the meantime, server push new cookies through the WS connection which are again set on the client-side and helps the process works on reload. But it fails if arbitrary code ables to wait for cookies to set. – litz Aug 15 '21 at 10:39
  • Yep, or runs before the deletion (and worse if the cookies were not HttpOnly). – CBHacking Aug 16 '21 at 06:11