URL의 식별자를 '복호화'한다는 착각

평문 합성 식별자 — 역파싱 대신 정방향 매칭

identitydata-modeling

난이도: ★★★☆☆ 연관 노트: URL을 진실의 원천으로


핵심 요약

  1. URL에 심은 식별자가 **암호화된 게 아니라 그냥 값들을 이어붙인 조합(평문)**이면, 되짚는 건 “복호화”가 아니다 — 그냥 **역참조(lookup)**다.
  2. 그 값을 거꾸로 파싱해서(예: 숫자 부분만 떼어 id로) 주체를 찾으려 하면 위험하다 — 식별자 종류가 여럿이고 형태가 겹치면(둘 다 숫자면) 어느 쪽인지 구분이 안 된다.
  3. 정답은 정방향 매칭: 내보내는 순간 (식별자 ↔ 내부 PK)쌍으로 로그에 기록해두고, 나중엔 그 로그에서 식별자로 행을 찾아 짝지어진 PK를 읽는다. 파싱 없음 → 종류 구분 없이 한 컬럼으로 균일하게 매칭.

왜 헷갈렸나

  • URL의 ?key=... 값을 보고 **“복호화해서 누군지 알아낸다”**고 표현 → 애초에 암호화한 적이 없으니 틀린 프레임.
  • “식별자에서 내부 id를 떼어내서 조회하면 되지” → 역파싱 발상. 근데 식별자가 두 종류였다:
    • 비회원: key = 내부 리드 PK (그냥 숫자)
    • 회원: key = 이름 앞 몇 글자 + 유저 id 를 이어붙인 합성값 앞 몇 글자가 우연히 전부 숫자면 회원 합성값도 순수 숫자로 보여서 → 비회원 PK와 형태가 구분 안 됨 → 역파싱하면 오귀속.

메커니즘

로그를 남길 때 key에 넣은 값(uid)과 내부 PK를 같은 행에 쌍으로 저장한다. 그러면 되짚기가 단 한 번의 매칭으로 끝난다.

send_log
  uid          | pk(lead_id)
  ─────────────┼────────────
  ab1298765    | 123         ← 회원: uid=합성값, pk는 별도 컬럼
  124861       | 124861      ← 비회원: uid=pk (같은 값이 두 컬럼에)

되짚기 (분기 없음, 한 방):
  분석 이벤트의 key  →  WHERE uid = key  →  그 행의 pk 를 읽음

핵심: 매칭 시점엔 이 key가 회원 합성값인지 비회원 PK인지 알 필요가 없다. uid 컬럼 하나에 뭘 넣었든 그대로 들어있으니, key = uid로 매칭하면 종류 불문하고 짝 PK가 딸려 나온다. “숫자면 PK로 취급” 같은 분기를 하는 순간 형태 충돌에 당한다.


해결 패턴

// 내보낼 때: uid와 내부 PK를 쌍으로 기록
await log.insert({ uid, lead_id, sent_at });

// 되짚을 때: 파싱하지 말고 매칭
// 이벤트.key = log.uid  →  같은 행의 lead_id 획득 (단일 조인)
SELECT e.key, l.lead_id
FROM events e JOIN send_log l ON l.uid = e.key

주의: 링크에 넣을 때 encodeURIComponent를 거쳤다면, 되짚기 전에 디코딩해서 raw uid로 매칭해야 한다(로그엔 raw로 저장돼 있으므로).


다음에 이 상황을 만나면

“URL/토큰에서 주체를 알아내야 한다” → 먼저 물어라: 이건 암호화된 건가, 평문 조합인가?

  • 평문이면 “복호화”가 아니라 lookup — 역파싱 유혹을 경계
  • 발행 시점에 (공개식별자 ↔ 내부키) 쌍을 기록해뒀나? → 있으면 정방향 매칭
  • 식별자 종류가 여럿인가? 형태가 겹칠 수 있나(둘 다 숫자)? → 파싱 분기 금지, 기록된 컬럼에 균일 매칭

커넥팅 닷

← 선행 개념 (이걸 알아야 이해된다)

  • URL을 진실의 원천으로 — 식별자를 URL 파라미터로 실어 나른다는 발상의 토대.
  • 암호화 vs 인코딩 vs 해싱 — “복호화”라는 단어를 쓰기 전에 셋을 구분해야. 조합은 셋 중 아무것도 아님.

→ 확장 개념 (여기서 더 나아가면)

  • 불투명(opaque) 식별자 설계 — 종류를 타입 접두어(u_, l_)로 명시하면 형태 충돌 자체가 사라진다. 여기선 안 했기에 정방향 매칭으로 우회.
  • surrogate key vs natural key — 왜 PK를 URL에 직접 노출하는 게 위험/애매한지.

↔ 같은 원리가 적용되는 곳

  • 로그를 “발생 시점 사실의 불변 기록”으로 쓰기 — 나중에 재계산·역추론하지 말고, 그 순간의 정답을 남겨 조회. (이벤트 소싱의 축소판)
  • 어트리뷰션 조인 — 광고/CRM에서 클릭↔전환을 잇는 것도 “발행 시 심은 식별자 ↔ 기록” 매칭.

참고