멜론티켓 세션 검증 메커니즘 분석

jjuyaa·2026년 1월 13일

티켓팅

목록 보기
1/1

JESSION

JSESSIONID 검증의 기본 원리

서버에서 발급한 세션ID를 모든 요청마다 검증하는 방식

Request Header 확인:
Cookie: JSESSIONID=

왜 콘솔에서 스크립트 실행이 차단될까?
브라우저 콘솔에서 document.createElement('script')로 API를 호출하면 새로운 세션이 생성되어 기존 세션이 무효화

이중 세션 시스템: 왜 JSESSIONID가 2번 발급될까?

멜론티켓은 용도가 다른 두 개의 JSESSIONID를 사용

로그인 세션 (일반 웹)

Domain: ticket.melon.com
Path: /
용도: 일반 웹 브라우징, 페이지 상태 관리

로그인 시 함께 발급되는 쿠키들:

  • MLCP (Melon Login Credential Package): JWT와 유사한 사용자 인증 토큰
  • keyCookie: 사용자 고유 식별자
  • MAC (Message Authentication Code): MLCP 위변조 검증용 암호화 정보
    티켓팅 세션 (예매 전용)
Domain: ticket.melon.com
Path: /reservation
  • 용도: 좌석 선택, 예매 상태 관리
  • 타임아웃: 5~10분?
    브라우저의 쿠키 전송 규칙
# 일반 페이지 접속
GET https://ticket.melon.com/concert/index.htm
Cookie: JSESSIONID=ABC123  (Path=/ 쿠키만)

# 티켓팅 팝업 접속
GET https://ticket.melon.com/reservation/popup/onestop.htm
Cookie: JSESSIONID=ABC123; JSESSIONID=XYZ789
        ↑ Path=/          ↑ Path=/reservation

서버는 더 구체적인 Path의 쿠키를 우선적으로 사용

티켓팅 플로우: 5단계 세션 관리

1. 로그인 (메인 세션)

https://ticket.melon.com (메인)
서버 → Set-Cookie 응답

Cookie 설정:
- MLCP(Melon Login Credential Package): 인증 토큰 (JWT 와 같은 사용자 인증 정보)
- keyCookie: 사용자 고유 ID (간단 식별자)
- MAC(Message Authentication Code): 암호화된 인증 정보 (MLCP 위변조 검증)
- JSESSIONID (일반 세션, Path=/)

2. 티켓 상품 페이지 접속

  • Set-Cookie 없음 -> 새 세션 생성 X, 기존 쿠키 사용

3. 예매하기 버튼 클릭 -> 대기열(NetFunnel)

🎫 NetFunnel이란?
대기열 관리 솔루션: 한국에서 티켓팅/예매 사이트(멜론, 인터파크, 예스24, YES24 등)가 거의 다 사용하는 트래픽 제어 시스템

  • 핵심 원리

    서버 처리 용량: 초당 100명
    실제 접속 시도: 초당 10,000명
    → NetFunnel 대기실에 9,900명 대기 → 선착순으로 100명씩 입장
  • 동작 방법

    1. 대기열 클릭 시 ts.wseq 요청이 날아감
      cookie 확인 시 NetFunnel_ID: 대기존 식별 (전역), TKT_POC_ID: 티켓팅 세션 식별 (티켓 도메인) 발급된 것 확인 가능
      - NetFunnel의 경우 set_cookie 방식이 아닌, javascript 방식으로 내부에서 쿠키 직접 설정
    2. 대기 중 폴링 (계속 확인)
    Request (2초마다 반복):
    GET https://nfp.melon.com/ts.wseq?opcode=5004&...
    Cookie: NetFunnel_ID=WP15; TKT_POC_ID=WP15
    
    Response Body:
    NetFunnel.gControl.result='5002:200:key=...&nwait=14532&nnext=120...';
                                                  ↑ 대기 인원 감소 중
    1. 대기 통과
    Response Body:
    NetFunnel.gControl.result='5002:200:key=...&nwait=0&nnext=0&complete=Y';
                                                  ↑ 대기 완료!
    
    이후:
    window.location.href = '/reservation/popup/onestop.htm?...';
    → 좌석 선택 팝업으로 리다이렉트

🔐 NetFunnel 검증 로직

// 좌석 API 호출 시

@GetMapping("/tktapi/product/seat/seatMapList.json")
public ResponseEntity<?> getSeatList(HttpServletRequest request) {
  
  // 1. NetFunnel 통과 확인
  String nfId = getCookie(request, "NetFunnel_ID");
  String tktPocId = getCookie(request, "TKT_POC_ID");
  
  if (nfId == null || tktPocId == null || !nfId.equals(tktPocId)) {
    return error("NF001", "대기열을 거치지 않은 접근입니다");
  }
  
  // 2. NetFunnel 서버에 검증 요청
  boolean isValid = netfunnelService.validate(nfId, userId);
  if (!isValid) {
    return error("NF002", "유효하지 않은 대기 티켓입니다");
  }
  
  // 3. 대기 완료 시간 확인 (5분 이내만 유효)
  long passedTime = netfunnelService.getPassedTime(nfId);
  if (passedTime > 300000) {  // 5분
    return error("NF003", "대기 완료 후 시간이 초과되었습니다");
  }
  
  // 모든 검증 통과
  return ResponseEntity.ok(seatData);
}

⚠️ NetFunnel 우회 불가능 이유

  • 쿠키 직접 생성 → 서버에서 검증 실패
  • NetFunnel 스크립트 건너뛰기 → API 호출 거부
  • 대기 완료 URL 직접 접근 → 쿠키 없어서 차단

NetFunnel은 자체 서버에서 티켓 발급부터 완료까지 모든 상태를 관리하므로 클라이언트 조작으로는 우회 불가

4단계: 좌석 선택 팝업 열림 ⭐ 핵심!

팝업 URL:
https://ticket.melon.com/reservation/popup/onestop.htm?prodId=&scheduleNo=

이때 서버가 JSESSIONID 발급:
↓
서버 → Set-Cookie: JSESSIONID=

이 JSESSIONID가 좌석 API 호출 시 검증에 사용됨!

💡 왜 팝업마다 새 JSESSIONID를 발급할까 ?
보안 + 격리 목적

// 서버 로직 (의사코드)

// onestop.htm 요청 시
if (request.getRequestURI().contains("onestop.htm")) {
  
  // 1. 기존 로그인 검증
  if (!isLoggedIn(request.getCookie("MLCP"))) {
    redirect("/login");
  }
  
  // 2. 티켓팅 전용 세션 생성
  HttpSession ticketSession = request.getSession(true);  // 새 세션 강제 생성
  ticketSession.setAttribute("prodId", request.getParameter("prodId"));
  ticketSession.setAttribute("scheduleNo", request.getParameter("scheduleNo"));
  ticketSession.setAttribute("startTime", System.currentTimeMillis());
  ticketSession.setMaxInactiveInterval(300);  // 5분 타임아웃
  
  // 3. JSESSIONID 쿠키로 반환
  response.addCookie(new Cookie("JSESSIONID", ticketSession.getId()));
}
  • 타임아웃 관리: 좌석 선택 5분 제한 등
  • 동시 세션 격리: 여러 탭에서 다른 공연 예매 시 충돌 방지
  • 보안 강화: 티켓팅 중에만 유효한 임시 세션
  • 상태 추적: 어떤 블록 클릭했는지, 몇 개 선택했는지 등

5. 좌석 API 호출 및 검증

모든 좌석 관련 API는 티켓팅 세션을 검증

브라우저 → GET /tktapi/product/seat/seatMapList.json?blockId=
          Cookie: JSESSIONID=
            ↓
서버      → 1. Cookie에서 JSESSIONID 추출
            2. sessions.get("")
            3. 존재하고 유효하면 → 데이터 응답
            4. 없거나 만료되면 → {"code":"T9110", "message":"올바른 접근이 아닙니다"}

정리

멜론티켓의 세션 관리는 3중 방어선으로 구성

  • 로그인 인증: MLCP, MAC 쿠키로 사용자 신원 확인
  • 대기열 검증: NetFunnel 쿠키로 정상 대기 경로 확인
  • 티켓팅 세션: JSESSIONID로 예매 진행 상태 관리

0개의 댓글