WebSocket Security

Introduction

WebSocket은 비 연결형 요청인 HTTP의 단점을 보와하여 서버와 브라우저가 실시간으로 통신할 수 있도록 만들어진 프로토콜로 HTTP 기반의 Handshake 이후 TCP/TLS를 통해 통신하며 데이터를 교환할 수 있습니다.

비슷한 기능으로 SSE (Server Sent Event)가 있습니다. SSE의 경우 일방향 통신을 위한 기술이고, WebSocket은 양방향 통신을 위한 기술입니다.

Handshake and Data transfer

WebSocket의 통신 과정은 Handshake 와 Data transfer로 나눌 수 있습니다.

Handshake

WebSocket은 기본적으로 웹 위에서 동작하기 때문에 HTTP 프로토콜을 통해 Handshake 과정이 시작됩니다. 브라우저에서 웹 서버로 Upgrade Request를 전송하게 되면, 서버는 브라우저에게 HTTP Response로 상태값을 전달하게 됩니다.

  • 101 Switching Protocols
  • 400 Bad Request
  • 415 Unsupported Media Type

성공 시 101 Switching Protocols을 리턴하면서 upgrade 헤더에 websocket으로 명시하여 브라우저가 WebSocket Connection을 연결하여 Data transfer 과정으로 넘어갑니다.

Data transfer

WebSocket Handshake 이후 Data transfer 과정은 일반 Socket 통신과 유사하게 특정한 포맷 없이 데이터를 전송/수신할 수 있습니다. Framework나 Library에 따라 추가적인 프로토콜을 사용하는 경우도 있습니다.

대표적으로 Springboot의 STOMP 프로토콜이 있습니다.`

WS:// and WSS://

http:// https:// 의 차이점 처럼 WebSocket도 ws:// wss:// 와 같이 비 암호화 소켓과 암호화 소켓으로 나뉩니다. 당연히 https:// 에서는 Mixed contents를 금지하고 있기 때문에 ws://로 강제 연결되지는 않습니다.

Example

if ('WebSocket' in window) {  
    var oSocket = new WebSocket("ws://localhost:80");

    oSocket.onmessage = function (e) { 
        console.log(e.data); 
    };

    oSocket.onopen = function (e) {
        console.log(open);
    };

    oSocket.onclose = function (e) {
        console.log(close);
    };

    oSocket.send(message);
    oSocket.close();
}

Offensive techniques

How to Testing

ZAP

WebSockets 에서 통신 과정을 확인할 수 있습니다. 조건에 맞추어 breakpoint를 걸어 디버깅하거나, Open/Resend with Message Editor를 통해 Manual testing을 진행할 수 있습니다. 이 때 outgoing, incoming 모두 가능합니다.

위와 같이 각 Connection은 # 으로 구별되며 통신 내용을 확인할 수 있습니다. 그리고 아래와 같이 outgoing, incoming 모두 데이터를 수정하여 브라우저나 서버로 전송할 수 있습니다.

추가로 ZAP의 Scripts 내 WebSocket Passive Rules, WebSocket Sender에 보면 미리 작성된 ZAP Script가 있습니다. 이를 활용하면 웹 소켓 통신에서도 원하는 데이터를 쉽게 걸러내고 확인할 수 있습니다.

위 이미지는 IDOR를 식별하는 Passive Rules인데, ZAP Context의 User에 등록된 계정 이름과 그에 대한 Hash 값들이 WebSocket 통신 과정에서 노출되는지 체크합니다. 노출된다면 이 값을 변경하여 다른 사용자의 데이터를 처리할 수 있는지 테스트할 IDOR의 포인트가 되겠죠 :D

Burpsuite

Proxy > WebSockets history에서 통신 과정을 확인할 수 있습니다. ZAP과 유사하게 Repeater로 보내서 Manual testing을 진행할 수 있습니다.

CLI

wscat이란 도구를 이용해서 cli 기반으로 WebSocket에 대해 테스트할 수 있습니다. 기본적인 연결, 이후 데이터 통신이 가능합니다.

npm install -g wscat

Browser Addon and Web

Chrome, Firefox 등의 Browser Addon(Extension)이나 일반 웹 페이지로도 쉽게 테스트 환경을 만들 수 있습니다. 아래는 Weasel이란 Firefox Addon입니다.

Testing Method

Injections

WebSocket 으로 통신되는 데이터는 다시 클라이언트와 서버와의 통신 과정이기 때문에 서버 로직에 따라서 SQL Injection, OS Command Injection 등 다른 여러가지 Attack과 연결됩니다. 기본적으로 서비스에서 사용하는 WebSocket 내부에서 사용되는 프로토콜을 파악하고 Injection 등에 대한 보안 테스팅을 진행해야 합니다.

SEND:THIS_IS_DATA' OR sleep(5);#

IDOR

WebSocket은 별도의 채널이기 때문에 초기 핸드쉐이크 이후 웹서비스에서 사용하는 쿠키나 세션등의 정보를 사용하지 않습니다. (사용 하더라도 Handshake 과정에서 전달합니다)

만약 WebSocket 통신 과정에서 식별자 정보 등이 사용되는 경우 IDOR에 취약할 가능성이 높습니다.

SEND:ID=test1234:CMD=updatePW:value=1234
SEND:ID=admin**:**CMD=updatePW:value=1234

CSWSH

CSWSH(Cross-Site WebSocket Hijacking)은 WebSocket 연결 시 CORS 정책의 미흡으로 발생하는 SOP 우회 취약점입니다. 이를 통해서 개발자가 의도하지 않는 사이트에서 WebSocket 연결 및 통신이 이루어질 수 있습니다. 자세한 내용은 아래 문서를 참고해주세요.

Cullinan > CSWSH(Cross-Site WebSocket Hijacking)

WebSocket Connection Smuggling

WebSocket Connection Smuggling은 WebSocket Handshake에서 오류 발생 시 TCP/TLS 터널이 구성되는 취약점입니다. 이를 통해서 Reverse Proxy 단의 보안정책을 회피하거나 내부 시스템 등을 접근할 수 있습니다. 자세한 내용은 아래 문서를 참고해주세요.

Cullinan > WebSocket Connection Smuggling

Etc

이외에도 Handshake, Data Transfer 과정에서 모든 웹 공격에 대해 테스트가 필요합니다.

Protocol over WebSocket

STOMP

STOMP는 Springboot에서 사용되는 WebSocket 프로토콜로 Data transfer 과정에서 사용되는 프로토콜입니다. 크게 아래와 같은 COMMAND를 가지고 있으며, Springboot를 사용하는 서비스에선 개발자가 별도로 검증하지 않는 이상 COMMAND를 모두 사용할 수 있어 주요 테스팅 포인트가 됩니다.

ABORT 
ACK 
BEGIN 
COMMIT 
CONNECT 
CONNECTED 
DISCONNECT 
ERROR 
MESSAGE 
NACK 
RECEIPT 
SEND 
STOMP 
SUBSCRIBE 
UNSUBSCRIBE

보통 CONNECT > SUBSCRIBE를 통해 하위 Topic(웹소켓 내 추가 채널)을 구독하고, 이후에 MESSAGE, SEND 등으로 데이터를 연결된 서버와 구성에 따라 다른 WebSocket Client에게도 전달할 수 있습니다.

Defensive techniques

가장 기초적인 방어 메커니즘은 외부로 부터 오는 요청을 모두 신뢰하지 않는 것입니다. 웹소켓은 설정에 따라서 인증되거나, 인증되지 않은 사용자가 예측 불가능한 데이터를 전송할 수 있다는 점을 인지하고 허용되지 않는 범위의 요청은 처리하지 않도록 보호 로직을 구성해야합니다.

Tools

  • ZAP - WebSockets
  • Burp - Proxy > WebSockets History
  • wscat
  • WebSocket Weasel
  • https://github.com/hahwul/websocket-connection-smuggler
  • https://github.com/hahwul/websocket-connection-smuggling-go

Articles