← posts/b.log()

blog92@web:~$ cat posts/websocket-10-authentication-and-authorization.md

NETWORK2 min read

WebSocket 완전 정복 10편 — 인증과 인가: 티켓 방식과 CSWSH 방어

쿠키·쿼리스트링 토큰·티켓·첫 메시지 네 가지 인증 방식을 주의사항과 함께 비교하고, Upgrade 단계에서 Origin을 검사하고 일회용 티켓을 소모하는 서버 코드, CORS가 적용되지 않아 생기는 CSWSH 공격의 원리, 그리고 연결 이후의 인가와 토큰 재검증을 다룹니다.

WebSocket 완전 정복 · 2부. 중급: 프로토콜 내부와 설계 패턴 · 16편 중 10편

이전 편: 9편 — 재연결 전략

9편까지가 끊긴 연결을 되살리는 쪽이었다면, 이번 편은 연결을 누구에게 열어 줄지 정하는 쪽입니다. 인증을 어느 단계에 두는지, CORS가 없는 WebSocket에서 Origin 검사가 왜 빠질 수 없는지, 그리고 연결이 성립한 뒤에도 권한 확인이 계속돼야 하는 이유를 봅니다.

인증 방식 네 가지

방식설명주의
쿠키같은 도메인이면 자동 전송CSWSH 방어(Origin 검사) 필수
쿼리스트링 토큰?token=...액세스 로그에 남음. 짧은 수명 일회용만
티켓 방식 (권장)HTTPS API로 30초 일회용 티켓 발급 → 그 티켓으로 접속 → 사용 즉시 폐기로그에 남아도 이미 무효
첫 메시지 인증연결 후 첫 메시지로 토큰 전송미인증 연결이 자원 점유 → 수 초 타임아웃 필요

인증은 연결 수락 전(Upgrade 단계)에 하는 것이 가장 좋습니다.

Upgrade 단계에서 인증하기

ts
import http from "node:http";
import { WebSocketServer } from "ws";
 
const server = http.createServer();
const wss = new WebSocketServer({ noServer: true });
const ALLOWED_ORIGINS = new Set(["https://app.example.com"]);
 
server.on("upgrade", async (req, socket, head) => {
  // 1) Origin 검사 (CSWSH 방어)
  if (!ALLOWED_ORIGINS.has(req.headers.origin ?? "")) {
    socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
    return socket.destroy();
  }
  // 2) 티켓 검증
  const url = new URL(req.url!, "http://localhost");
  const user = await consumeTicket(url.searchParams.get("ticket"));
  if (!user) {
    socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
    return socket.destroy();
  }
  wss.handleUpgrade(req, socket, head, (ws) => {
    wss.emit("connection", ws, req, user);
  });
});
 
server.listen(8080);
 
declare function consumeTicket(t: string | null): Promise<{ id: string } | null>;

CSWSH — WebSocket에는 CORS가 없다

WebSocket에는 CORS가 적용되지 않습니다. 악성 사이트가 new WebSocket("wss://your-app.com/ws")를 열면 브라우저가 사용자 쿠키를 실어 보냅니다. 쿠키만으로 인증하면 공격자가 사용자 권한으로 통신할 수 있습니다. Origin 허용 목록 검사로 방어합니다.

인가 — 연결 시 인증으로 끝이 아니다

연결 시 인증으로 끝이 아닙니다. 채널 구독·메시지마다 권한을 확인하고, 장기 연결은 토큰 만료에 맞춰 재검증하거나 4000번대 코드로 끊습니다.

더 깊이

  • 풀스택 개발자를 위한 네트워크 8장 — 브라우저 보안 모델: SOP, CORS, 쿠키: 이 편이 전제로 깔고 지나간 것들의 출처입니다. Origin이 무엇으로 정해지는지(8.2), 일반 HTTP 요청에서는 CORS가 어떻게 막아 주는지(8.3), 쿠키가 자동으로 실리는 조건과 SameSite(8.4), CSRF(8.5)를 봐 두면 CSWSH가 그 방어막이 없는 자리에서 같은 구조로 일어나는 공격이라는 것이 보입니다.
  • 4편 — 브라우저 API: 브라우저 API는 임의의 헤더를 설정할 수 없다는 제약이 이 편의 출발점입니다. 쿠키·쿼리스트링·티켓·첫 메시지 네 가지는 전부 Authorization 헤더를 붙일 수 없어서 생긴 우회로입니다.
COMMENTS (…)

댓글을 불러오는 중이에요.

NEW COMMENT0 / 1000
⌘↵ 전송

blog92@web:~$ cd ..