Monday, July 22, 2019

Cross-Site WebSocket Hijacking

Introduction

  • WebSocket is an HTML5 feature, which enables full-duplex communication over a single TCP connection between browser and server.
  • WebSocket allows you to exchange text and binary messages pushed from the server to the browser as well as vice versa.
  • WebSockets are mostly used in chat environments.
  • In order to create a full-duplex communication the web socket protocol requires a handshake that is carried over http:// or https:// to switch towards web socket protocol.
  • This handshake effectively upgrades the communication protocol to ws:// (or wss:// for SSL protected channels).
  • Same-origin policy is not enforced on WebSocket via a browser.


Working of Web Sockets

  • An HTTP(S) WebSocket handshake request is sent from the client side.
  • The server replies with a handshake response and sends a response status code of 101 Switching Protocols.
  • From that point on both browser and server communicate using WebSocket API with a completely symmetrical connection (each party can send and retrieve text and binary messages).


Impact

  • Because WebSockets are not restrained by the same-origin policy, an attacker can easily initiate a WebSocket request (i.e. the handshake/upgrade process) from a malicious webpage targeting the ws:// or wss:// endpoint URL of the attacked application. Due to the fact that this request is a regular HTTP(S) request, browsers send the cookies and HTTP-Authentication headers along, even cross-site. 
  • If a user is already logged in to the vulnerable application from his/her browser and has http://attacker.com open in a different tab then http://attacker.com can try to create a WebSocket connection with the vulnerable application and the valid authenticated Session ID will be sent (by the browser) along with this request. So the WebSocket connection, which is now established by http://attacker.com, will have the same level of access as the WebSocket created from within the vulnerable application.


How to Test?

To test this flaw all we need to do is to send another request with a modified Origin header. If we received 101 Web Socket Protocol Handshake then it means the WebSocket connection has been established.
  • If the connection is not established then it means the application is secure as it is rejecting WebSocket connections from external Origins. 
  • If the connection is established then we would have to perform further checks to confirm if the application is vulnerable to Cross-Site WebSocket Hijacking. 
  • Even if a connection is established the application is only vulnerable when it responds to WebSocket messages like it does for a connection from valid Origin. This is because the developer could have placed the Origin verification logic along with the access control checks. So the connection would still be established but external Origins won’t have access to authenticated data in such cases which is a good thing.

You can also use the add-on "Browser WebSocket Client" or visit https://ironwasp.org/cswsh.html.

CSRF and CORS

  • CSRF
    • This is very similar to a Cross-Site Request Forgery (CSRF) attack. 
    • But in the WebSocket scenario, this attack can be extended from a write-only CSRF attack to a full read/write communication with a WebSocket service by physically establishing a new WebSocket connection with the service under the same authentication data as the victim.
  • CORS
    • An Origin header is been sent along with the WebSocket handshake request.
    • This is like in a regular CORS request utilizing Cross-Origin Resource Sharing: If this was a regular HTTP(S) CORS request, the browser would not let the JavaScript on the malicious web page see the response when the server does not explicitly allow it (via a matching Access-Control-Allow-Origin response header).
    • But when it comes to WebSockets this "fail close" style of defaulting to "restrict response access" when the server does not explicitly allow cross-origin requests is inverted:
    • In our example, the server did not send any CORS response headers along, but the cross-site WebSocket request response is still handled by the browser by properly establishing the full-duplex WebSocket connection.
    • This demonstrates that WebSockets are not protected by the same-origin policy (SOP), so developers must not rely on SOP protection when it comes to developing WebSocket based applications. 
    • Clearly, the CORS stuff has nothing to do with the WebSockets stuff, but they both utilize the same request header (Origin) and the server-side code should check that header.

Mitigation


An application can be secured against Cross-Site WebSocket Hijacking in two ways:
  • Check the ‘Origin’ header of the request. Since this header was designed to protect against cross-origin attacks. If the ‘Origin’ is not trusted, then simply reject the request. For example: If your site has the domain as www.example.com, then check if the request originates from that origin, if yes, then process it. If no, then reject it.
  • Use session-individual random tokens (like CSRF-Tokens) on the handshake request and verify them on the server. Generate them server-side and have them in hidden fields on client-side. And verify them at request.
If you don't need to access the web session from the server-side WebSocket counterpart, just separately handle authentication and/or authorization using custom tokens or similar techniques within your WebSocket protocol and avoid relating to the web session via cookies or HTTP-Authentication during the handshake request.