개발 삽질 일지

[크롬 익스텐션] 직링 구하기 본문

자유로운 개발일지/실험일지

[크롬 익스텐션] 직링 구하기

그낙이 2025. 5. 17. 21:49
반응형

이번 글에서는 직링에 대해서 다뤄보겠습니다. 공연이나 콘서트 예매를 하다 보면, 예매 시작 시간에 수많은 사람들이 몰리면서 접속이 안되는 경우가 있으셨을 겁니다. 이 혼란 속에서 자주 등장하는 단어가 직링입니다. 개발자로서 이 직링이 어떤 원리로 작동하는지, 그리고 어떻게 추적할 수 있는지 파헤쳐보려고 합니다. 

 

⚠️ 이 글은 기술적인 호기심과 실험적인 분석을 위한 목적으로 작성되었습니다. 실제 예매 과정에서 이를 악용하거나 무단으로 활용하는 것은 서비스 약관 위반이 될 수 있으며, 법적 책임이 따를 수 있습니다. 또한, 이번 글에서는 코드 구현보다는 개념과 작동 원리에 집중하니 가볍게 읽어주시길 바랍니다.

 

직링이란?

직링이란 직접 링크의 줄임말로 티켓 예매 절차 중 좌석 선택 화면으로 곧바로 진입할 수 있는 링크(URL)을 의미합니다. 일반적인 티켓 예매 절차는 다음과 같습니다. 

메인페이지 → 로그인 → 공연 상세 페이지 → 날짜/시간 선택 → 예매 버튼 클릭 → 좌석 선택 → 결제

 

하지만, 직링은 일부 과정을 생략하고 곧바로 좌석 선택 화면으로 이동합니다. 즉, 예매 버튼을 누르지 않고, 좌석 화면에 접근하는 지름길입니다. 그렇다보니 많은 사람들 사이에서 직링을 모르면 티켓 예매에서 백전백패한다는 말도 나오고 있습니다.

 

‘댈티·아옮·직링’ 모르는 당신, 티켓 예매 ‘백전백패’…어쩌다 이 지경?

# 오모씨는 12만원대인 SM타운 주최 아이돌 콘서트 티켓을 20만원 초반대에 구매할 수밖에 없었다. 좌석은 3층이었지만 주변에서는 꽤 합리적인 ‘플미’(프리미엄) 티켓이라고 반…

www.donga.com

 

 

직링을 아는 방법은?

그렇다면 직링을 어떻게 알아낼 수 있을까요? 결론부터 말하자면 좌석 선택 화면의 URL을 복사해서 붙여넣는 것 만으로는 작동하지 않는 경우가 많습니다. 그 이유는 대부분의 예매 사이트에 다양한 보안 장치가 있기 때문입니다. 

 

직링은 보통 다음과 같은 흐름으로 추론할 수 있습니다.

1. 공연 상세 페이지 → 예매 버튼 클릭 → 좌석 선택 화면 진입 

2. 개발자 도구(F12)를 열고 Network 탭 확인 

3. 좌석 선택 화면으로 전환되는 순간, 호출되는 특정 URL 확인 

4. 해당 URL에 아이디, 좌석 정보, 보안 장치 등의 파라미터(변수)가 포함되어 있다면 가능성이 높습니다. 

https://ticket.example.com/seat?perfId=12345&sessionToken=abcde...

 

이러한 URL을 복사해서 새로운 창에서 열어보면 로그인 페이지로 리다이렉트 되거나, 비정상적인 접근이라는 메시지가 나오게 되는데, 이는 로그인 상태, 세션 정보 등 유효성 검사를 통과하지 못하기 때문입니다. 

 

예매 흐름

정상적인 티켓 예매 흐름을 보고, 이를 통해서 어떤 값들이 필요한지 그리고 어떻게 얻을 수 있는지 찾아봅시다.예매하기 버튼을 클릭했을 때, 어떤 값들이 POST 되는지를 확인해보겠습니다. 제가 데이터를 얻은 사이트는 예매하기를 눌렀을 때, 좌석 선택을 위한 새로운 창이 열리게 되는 구조였습니다. (타 사이트들은 다른 구조일 수 있습니다.) 브라우저에 팝업이 뜨는 순간 콘솔에 출력할 수 있도록 간단한 코드를 작성해봅시다. 

const originalOpen = window.open;
window.open = function (...args) {
  console.log("팝업 열림", args);
  return originalOpen.apply(this, args);
};

 

아래는 콘솔에 찍힌 결과입니다.

{
  "url": "",
  "target": "sample_target"
  "features": "width=950px,height=646px"
}

 

그렇다면 sample_target으로 데이터를 보낼 때, 필요한 변수들을 확인해봅시다 .

const original_submit = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = function () {
  if (this.target === "sample_target") {
    console.log("Action:", this.action);
    console.log("Method:", this.method);
    console.log("Target:", this.target);
    const fd = new FormData(this);
    for (const [k, v] of fd.entries()) {
      console.log(`${k}: ${v}`);
    }
  }
  original_submit.call(this);
};

 

아래는 출력값입니다. 임의로 몇가지 변수들을 지우고, 변수 명도 수정했습니다. 여기서 알 수 있는건, ticket.sample.com으로 POST 요청을 보내면서, request params에 id, code, token을 보내는 걸 확인할 수 있습니다. 이제 저 값들만 찾아온 뒤, 요청을 보내면 예매 날짜, 시간을 건너뛰고 바로 좌석 선택 페이지로 이동하게 됩니다. 

Action: https://ticket.sample.com/reservation/ticket/sample.htm
VM466:6 Method: post
VM466:7 Target: sample_target
VM466:10 id: sample_Id
VM466:10 code: sample_code
VM466:10 token: sample_token

 

앞서 언급드린 것과 같이 이번 글에서는 구현보다는 개념과 작동 원리가 주 목적이니 개발 과정은 생략하겠습니다. 필요한 값들을 찾고, 예매 페이지 콘솔에서 입력하면 짜잔 하고 팝업창이 떴습니다. 


까지가 이제 완전히 개발향 첨가된 이야기고 아래는 어느정도는 개발이 가미된 이야기입니다.

 

1. 우선 대부분의 티켓 예매 사이트 URL에 id 혹은 code(id로 부르겠습니다) 값이 들어갑니다. 그렇다면 가정 첫 번째로, id가 포함되어 있을 때만 하위 코드를 실행하도록 짜줍시다. 예매 페이지에 정상적으로 들어온 경우에만 코드가 실행되게 됩니다. 

  const current_Url = window.location.href;
  if (!/id=|code=/i.test(current_Url)) {
    console.log("URL에 id 또는 code가 포함되어 있지 않아 실행하지 않음");
    return;
  }

 

2. 예매 버튼의 활성화 여부를 확인합시다. 사이트마다 활성화 여부는 다르지만, 색상으로 구분 지은 경우가 대부분이였던 것 같습니다. 아닌 경우에는, 버튼이 존재하지 않고 텍스트만 있는 경우도 있었습니다. 예매 버튼이 활성화(버튼 존재 유무 or 색상) 될 때만 팝업창을 띄우도록 코드를 작성합니다. (테스트한 사이트에서는 버튼이 존재했을 때만 토큰 값을 받아올 수 있게 되어있었습니다. 그래서 토큰 값을 못받아오면 polling 방식으로 계속 요청하고, 값을 받아오면 다음으로 넘어갑니다.)

  const get_token = async () => {
    try {
      const res = await fetch(
        `https://sample_url.com/api/product/Id=${Id},
        {
          method: "GET",
          credentials: "include",
        }
      );
      const data = await res.json();
      const token = data.key;
      if (!chk) {
        setTimeout(() => get_token(), 100);
      }

 

변경 감지에 MutationObserver을 사용할 수도 있습니다. 하지만 DOM 변경 감지 방식에서 버튼이 새로 추가되는게 아닌, 클래스 명의 변경으로 CSS가 바뀌게 되면, 감지하지 못할 수 있어서 polling 방식을 채택했습니다. 

 

그러면 이제 특정 페이지에 도달했을 때, 특정 시간이 지났을 때만 코드가 실행되도록 구현이 완료되었습니다. 

이제 팝업창을 띄우는데 실패한 경우에, 재시도를 하는 코드를 작성하고 마무리지읍시다. 

const popup = window.open("", "sample_url", "width=950,height=646");

if (!popup) {
  get_token();
}

 

번외

이제 예매하고자 하는 페이지에서 로그인한 상태로 콘솔에 코드를 입력하면, 예매 팝업이 뜰 때까지 계속 호출하는 구조가 완성되었습니다. 하지만 개발자 도구를 키고 계속 코드를 복사 붙여넣기 하기 귀찮으니, 구글 익스텐션에 등록해봅시다. 

 

우선 코드가 들어있는 폴더가 필요합니다. 구조는 다음과 같습니다. 

ticket-extension/
├── manifest.json
├── content.js
└── (옵션) icon.png
# manifest.json

{
  "manifest_version": 3,
  "name": "직링",
  "version": "1.0",
  "description": "좌석 선택 페이지로 이동하는 URL을 감지합니다.",
  "permissions": ["scripting"],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ]
}

 

이후 chrome://extensions에 접속합니다. 우측 상단에 개발자모드를 켜주고, 압축해제된 확장 프로그램을 로드합니다. 선택 후, 파일을 업로드해주면 끝입니다.

 

지금까지 직링의 개념, 추론 방법, 그리고 개발자 도구를 활용한 분석 흐름까지 살펴보았습니다. 다시 강조하지만, 이 글은 기술적인 이해를 높이기 위한 목적이며, 실제 예매에서의 무단 활용은 절대 지양해야 합니다. 좌석을 가장 빠르게 잡는 비결은 결국 “직링”이 아니라, 공정한 접근과 좋은 운일지도 모릅니다.

 

언제나처럼 — 시작은 삽질이지만, 끝은 지식입니다.

 

반응형