UUID & 랜덤 토큰 생성기

UUID v1·v4·v7을 생성하고, 이미 가진 UUID가 어떤 버전인지 분석합니다.

UUID 생성

UUID 분석기

랜덤 HEX 토큰

UUID의 구조: 128비트를 어떻게 나누나

UUID(Universally Unique Identifier)는 128비트 값이며, 보통 8-4-4-4-12자리 16진수를 하이픈으로 이어 36자로 표기합니다. 현재 표준은 2024년 5월에 발행된 RFC 9562로, 기존 RFC 4122를 대체하면서 v6·v7·v8을 새로 정의했습니다. 어떤 버전이든 두 위치는 항상 같은 의미를 갖습니다.

따라서 UUID v4와 v7은 128비트 중 6비트(버전 4 + 변형 2)가 고정이고 나머지 122비트가 값을 결정합니다. 위의 "UUID 분석기"에 값을 넣으면 이 두 위치를 읽어 버전과 변형을 알려 줍니다. 모든 비트가 0인00000000-0000-0000-0000-000000000000은 Nil UUID, 모든 비트가 1인ffffffff-ffff-ffff-ffff-ffffffffffff는 Max UUID로 RFC 9562에 정의된 특수 값입니다.

v1, v4, v7 비교

버전구성무작위 비트정렬유의점
v160비트 시각(1582-10-15 기준, 100ns 단위) + 14비트 클록 시퀀스 + 48비트 노드없음(노드를 무작위로 대체 가능)시각이 앞쪽이 아니어서 문자열 정렬은 시간순이 아님MAC 주소를 노드로 쓰면 생성 시각과 장비 정보가 노출됨
v46비트 고정 + 122비트 무작위122무작위가장 단순하고 널리 지원됨. 시각 정보 노출 없음
v748비트 Unix 밀리초 + 4비트 버전 + 12비트 rand_a + 2비트 변형 + 62비트 rand_b74(같은 밀리초 안)생성 시각 순(밀리초 단위)생성 시각이 값에 드러남. 같은 밀리초 내 순서는 구현에 따라 다름

v7의 시각 필드는 48비트 밀리초이므로 248ms, 즉 약 8,919년 분량이며 서기 10889년까지 표현합니다. v1의 시각은 1582년 10월 15일(그레고리력 시작일)부터 센 100나노초 틱이라서 Unix 시각과의 차이 122,192,928,000,000,000틱(12,219,292,800초)을 더하거나 빼서 변환합니다. 이 페이지의 v1은 장비 식별 정보가 새지 않도록 노드 값을 무작위로 만들고 멀티캐스트 비트를 1로 설정합니다. 이는 RFC가 허용하는 무작위 노드 방식입니다.

충돌 확률: 계산 가능한 만큼만

무작위 비트가 b개일 때 n개를 만들어 하나라도 겹칠 확률은 생일 문제 근사식p ≈ n² / (2 · 2b)로 구합니다. v4는 b = 122이므로 아래 표와 같습니다(n이 충분히 작을 때 유효한 근사).

생성 개수 nv4 충돌 확률 p
1,000,0009.4×10^-26
1,000,000,0009.4×10^-20
1,000,000,000,0009.4×10^-14
1,000,000,000,000,0009.4×10^-8

10억 개를 만들어도 확률은 약 10-19 수준입니다. 충돌 확률이 50%에 이르려면 약 2.7×10^18개가 필요하며, 초당 10억 개씩 약 86년 동안 계속 생성해야 하는 양입니다. 충돌 확률을 10억분의 1로 유지할 수 있는 최대 개수는 약 1.0×10^14개입니다. 단, 이 계산은 난수 생성기가 정말 균일하고 예측 불가능하다는 전제에서만 성립합니다. Math.random() 같은 비암호학적 난수나 시드가 같은 가상머신 복제본에서는 실제 충돌 위험이 훨씬 커질 수 있습니다. 이 도구는 브라우저의 crypto.getRandomValues()(또는 crypto.randomUUID())를 사용합니다.

v7의 경우 서로 다른 밀리초에 만든 값은 시각 필드가 달라 겹치지 않고, 같은 밀리초에 만든 값끼리만 무작위 공간에서 충돌 가능성이 생깁니다. 이 도구는 같은 밀리초 안에서 12비트 카운터를 증가시켜 한 번에 만든 묶음이 정렬된 상태를 유지하게 합니다(RFC 9562가 허용하는 방식 중 하나).

DB 기본키로 쓸 때: 정렬과 인덱스

대부분의 RDBMS는 기본키를 B-트리로 저장합니다. 값이 단조 증가하면 새 행이 항상 트리의 오른쪽 끝 페이지에 붙지만, 완전 무작위인 v4는 트리의 임의 위치에 끼어듭니다. 그 결과 다음과 같은 비용이 생깁니다.

v7을 DB 함수로 직접 제공하는 DBMS도 있고(버전에 따라 다르므로 사용 중인 DB 문서 확인 필요), 없는 경우 애플리케이션에서 생성해 넣을 수 있습니다. 반대로 v7은 생성 시각이 값에 그대로 드러납니다. 주문번호처럼 외부에 노출되는 ID로 쓰면 발급 시각과 대략적인 발급량이 유추될 수 있으므로, 노출이 부담이면 내부 키는 v7, 외부 공개용은 별도 무작위 토큰으로 나누는 설계가 흔합니다.

흔한 실수와 오해

랜덤 HEX 토큰은 언제 쓰나요?

API 키, 세션 ID, 비밀번호 재설정 링크, CSRF 토큰처럼 추측 불가능해야 하는 값이 필요할 때 사용합니다. 바이트 n개를 16진수로 표기하면 문자 수는 2n개이고 엔트로피는 8n비트입니다. 16바이트는 128비트, 32바이트는 256비트입니다. UUID v4(122비트)보다 16바이트 토큰(128비트)이 약간 더 큰 공간이고, 형식 제약이 없어 URL·헤더에 그대로 쓰기 편합니다. 토큰은 생성 즉시 해시(예: SHA-256)로 저장하고, 원문은 사용자에게만 한 번 보여주는 방식이 안전합니다. 해시 계산은해시 생성기에서 확인해 볼 수 있습니다.

사람이 입력하는 비밀번호가 필요하다면 비밀번호 생성기를, 토큰을 JWT 형태로 발급하는 경우의 구조는 JWT 디코더를, v7 안에 든 밀리초 시각을 사람이 읽는 날짜로 바꿔 보려면 Unix 타임스탬프 변환기를 이용하세요. UUID 형식 검증용 정규식을 만들 때는 정규식 테스터가 편리합니다. UUID 정규식 예: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ (대소문자 무시 옵션 필요).

검산 예시

예시 1 (v4 구조): f47ac10b-58cc-4372-a567-0e02b2c3d479의 세 번째 그룹 첫 글자가 4이므로 v4, 네 번째 그룹 첫 글자가 a(2진수 1010, 상위 두 비트 10)이므로 RFC 변형입니다.

예시 2 (v7 시각 읽기): v7의 앞 12자리(하이픈 제외)가 48비트 밀리초입니다. 예를 들어 앞 12자리가018f1b2c3d4e이면 10진수로 1,714,147,835,214이며, 이는 2024-04-26 16:10:35.214 UTC입니다. 위 분석기에 018f1b2c-3d4e-7abc-8def-0123456789ab를 붙여넣으면 같은 결과가 나옵니다.

자주 묻는 질문

생성된 값이 서버에 저장되나요?

아니요. 브라우저 안에서만 생성되며 어디에도 전송되거나 저장되지 않습니다.

UUID가 겹칠 가능성이 있나요?

수학적으로 0은 아니지만 v4는 122비트 무작위 공간이라, 위 표처럼 10억 개를 만들어도 약 10-19 수준입니다. 실무 위험은 확률보다 난수 생성기 품질 문제에서 생깁니다.

UUID와 GUID는 다른 건가요?

GUID는 마이크로소프트 계열에서 쓰는 이름으로, 같은 128비트 구조입니다. 다만 일부 환경은 처음 3개 필드를 리틀 엔디언 바이트로 저장하므로, 바이트 배열로 주고받을 때 순서가 뒤바뀌지 않는지 확인해야 합니다.

DB 기본키는 v4와 v7 중 무엇이 좋은가요?

쓰기가 많은 대용량 테이블이라면 삽입 위치가 한쪽으로 모이는 v7이 인덱스 측면에서 유리합니다. 반면 생성 시각 노출이 문제이거나 이미 v4로 운영 중이고 규모가 작다면 굳이 바꿀 필요는 없습니다. 실제 성능은 DB 종류와 데이터 규모에 따라 달라지므로 자신의 환경에서 측정해 보세요.

하이픈을 빼도 같은 UUID인가요?

네. 하이픈은 표기용일 뿐 32자리 16진수가 값의 전부입니다. 다만 저장·비교 방식을 하나로 통일하지 않으면 같은 값이 다른 문자열로 취급될 수 있습니다.

HEX 토큰과 UUID 중 API 키로 적합한 것은?

API 키처럼 추측되면 안 되는 값은 형식이 고정된 UUID보다 32바이트 이상의 랜덤 HEX(또는 Base64URL) 토큰이 낫습니다. UUID는 식별 목적, 토큰은 인증 목적으로 구분해 쓰는 것이 원칙입니다.