본문 바로가기

UUID 생성

안전하게 — 파일은 저장되지 않아요

어떤 버전인가요?

형식
UUID 0개

여기에 UUID 0개 내용이 표시돼요.

사용 방법

1

버전 선택

추측할 수 없어야 하는 곳에는 v4, 데이터베이스 키에는 v7. 차이는 당연하게 넘어가지 않고 페이지에서 설명해 드립니다.

2

개수 선택

하나부터 최대 1만 개까지 한 번에 만들 수 있으며, 대문자, 중괄호, 하이픈 없음, 코드에 바로 쓸 수 있는 따옴표 목록 등 형식도 고를 수 있습니다.

3

복사하기

전부 복사하거나 텍스트 파일로 다운로드하세요.

버전 4냐 버전 7이냐, 그리고 데이터베이스에서 그것이 중요한 이유

UUID는 128비트이며, 익숙한 8-4-4-4-12 묶음의 16진수 32자리로 씁니다. 그중 6비트는 버전과 변형(variant)을 나타내는 데 쓰이므로, 버전 4에는 무작위 비트 122개가 남습니다. 1초에 10억 개씩 100년 동안 만들어도 같은 값이 두 번 나올 가능성은 극히 낮을 만큼 충분한 양입니다. 이것이 UUID의 매력의 전부입니다. 서로 통신한 적 없는 두 시스템이 각자 식별자를 만들어도 절대 충돌하지 않는다고 안심하고 가정할 수 있습니다.

그러려면 무작위성이 진짜여야 하며, 여기서는 일반 난수 생성기가 아니라 암호학적 난수 생성원에서 가져옵니다. 이 차이는 비밀번호 재설정 링크나 추측할 수 없는 공유 URL처럼 식별자를 권한 토큰으로 쓸 때 중요합니다. 예측 가능한 생성기라면 이전 값들로 다음 값을 알아낼 수 있기 때문입니다. 암호학적 생성원에는 예측할 것이 없습니다.

버전 7이 존재하는 이유는 버전 4가 데이터베이스 기본 키로 쓰기에 좋지 않기 때문입니다. v7은 앞부분에 48비트 밀리초 타임스탬프를 두고 나머지를 무작위 값으로 채우므로, 차례로 생성한 UUID가 만들어진 순서대로 정렬됩니다. 겉보기만의 차이 같지만 그렇지 않습니다. 무작위 키는 삽입할 때마다 인덱스 전체에 흩어지므로 쓰기마다 다른 페이지를 건드리고 캐시가 도움이 되지 않지만, 시간순 키는 한쪽 끝에 이어 붙습니다. 큰 테이블에서는 삽입 처리량의 차이가 상당하며, 이것이 v7이 표준화된 이유입니다.

대가도 분명히 있으니 따져 볼 만합니다. 버전 7 UUID는 그것을 보는 누구에게나 대략 언제 만들어졌는지를 밀리초 단위까지 알려 주며, 연속된 값을 보면 레코드를 얼마나 빨리 만드는지도 드러납니다. 내부 키라면 괜찮습니다. 하지만 주문 번호, 문서 링크, 사용자 ID처럼 URL에 노출되는 식별자라면 버전 4에는 없는 작은 정보 유출입니다. 둘 다 중요하다면 기본 키에는 v7을, 공개되는 값에는 v4를 쓰세요.

다른 작업이 필요할 때

UUID는 쓰는 곳에서 생성하세요. 모든 데이터베이스와 언어에 이 기능이 내장되어 있습니다. PostgreSQL은 gen_random_uuid(), MySQL은 UUID(), JavaScript는 crypto.randomUUID(), Python은 uuid.uuid4()입니다. 브라우저에서 한 묶음을 만들어 코드에 붙여 넣는 것은 테스트 데이터나 테스트에는 괜찮지만, 실제로 실행되는 코드에는 맞지 않습니다.

v7을 쓰려는 이유가 정렬 가능한 키라면 알아 둘 만한 대안이 있습니다. ULID는 같은 아이디어를 더 짧고 대소문자를 구분하지 않는 26자로 표현합니다. Snowflake 식별자는 64비트에 들어가므로 UUID의 128비트에 비해 인덱스 크기가 절반입니다. 그리고 많은 데이터베이스에서 평범한 자동 증가 정수가 여전히 이들 중 어느 것보다 빠르고 작습니다. UUID는 식별자를 여러 곳에서 동시에 만들어야 할 때 그 비용만큼의 가치가 있으며, 그렇지 않다면 아닙니다.

자주 묻는 질문

v4와 v7 중 무엇을 써야 하나요?

데이터베이스 기본 키라면 v7입니다. 비밀번호 재설정 링크, 초대 코드, 세션 식별자처럼 추측이 불가능해야 한다면 v4입니다. 결정할 것은 이것뿐인데, 거의 모든 생성기가 v4만 제공하기 때문에 대부분의 사람은 선택지가 있었다는 것조차 모릅니다.

v4는 왜 데이터베이스 키로 좋지 않나요?

완전히 무작위인데 데이터베이스 인덱스는 정렬되어 있기 때문입니다. 새 무작위 키는 인덱스의 아무 곳에나 들어가므로 삽입할 때마다 다른 페이지를 건드리고, 캐시가 도움이 되지 않으며, 인덱스가 파편화되고 커집니다. 크고 바쁜 테이블에서는 시간이 지날수록 심해지는, 측정 가능한 속도 저하입니다. 이론상의 걱정이 아닙니다. 그래서 이제 Postgres와 MySQL 문서 모두 이 문제를 다룹니다.

UUID v7이란 무엇인가요?

앞의 48비트가 밀리초 단위 타임스탬프이고 그 뒤를 무작위 값이 채우는 UUID입니다. 여전히 전역적으로 고유하고 128비트이지만, 시간이 앞에 오기 때문에 v7 UUID는 만들어진 순서대로 정렬됩니다. 새 키가 인덱스 곳곳에 흩어지지 않고 끝에 이어 붙으며, 이는 자동 증가 정수가 동작하는 방식과 똑같으면서 UUID의 고유성까지 갖춘 것입니다. 2024년 RFC 9562로 표준화되었으며, 새 테이블에 현재 권장되는 방식입니다.

여기서 만든 v7 UUID는 정말 정렬되나요?

네, 같은 밀리초 안에서도 정렬됩니다. 대부분의 구현이 잘못하는 부분이 바로 이것입니다. 타임스탬프는 밀리초 단위밖에 안 되므로, 반복문으로 ID 천 개를 만들면 1밀리초 안에 끝납니다. 하위 비트가 순전히 무작위라면 그 천 개는 만들어진 순서대로 정렬되지 않습니다. 이 생성기는 RFC 9562에 설명된 단조 증가 카운터를 사용하므로, 한 번에 만든 묶음은 매번 엄격한 오름차순입니다. 천 개를 만들어 정렬해 보세요. 만들어진 순서 그대로 돌아옵니다.

v7 UUID를 공개해도 안전한가요?

한 가지만 염두에 두세요. 설계상 만들어진 시각이 밀리초 단위까지 드러납니다. 데이터베이스 키라면 대개 무해하거나 오히려 유용합니다. 하지만 생성 시각 자체가 민감하거나 식별자를 추측할 수 없어야 한다면 v4를 쓰세요. v7에도 무작위 비트가 74개나 있어 충분히 많지만, 타임스탬프는 ID를 가진 누구나 그대로 읽을 수 있습니다.

보안상 충분히 무작위인가요?

네. 무작위성은 `Math.random`이 아니라 브라우저의 암호학적으로 안전한 생성기인 `crypto.getRandomValues`에서 가져옵니다. 이 차이는 실제 취약점으로 이어진 적이 있습니다. `Math.random`은 빠르지만 예측 가능하며, 이를 바탕으로 만든 세션 토큰이 실제로 추측된 사례가 있습니다. v4 UUID에는 무작위 비트가 122개 있어 충돌은 현실적으로 걱정할 필요가 없습니다.

제 기기에서 생성되나요?

네, 전부 기기에서 생성되며, 식별자에서는 이 점이 중요합니다. 다른 사람의 서버에서 받아 온 UUID는 다른 누군가가 이미 본 UUID입니다. 비밀 값을 만드는 중이라면 목적 자체가 무너집니다. 여기서 만든 값은 브라우저 밖으로 나가지 않습니다. 페이지를 불러온 뒤 Wi-Fi를 꺼도 똑같이 작동합니다. 저희 말을 믿는 대신 개인정보 보호 주장을 직접 확인하는 가장 간단한 방법입니다.

nil UUID란 무엇인가요?

모든 자리가 0인 00000000-0000-0000-0000-000000000000입니다. null을 쓸 수 없는 곳에서 “없음”이나 “설정되지 않음”을 뜻하는, 유효한 예약 UUID입니다. 그 반대인 모든 자리가 f인 max UUID는 정렬 경곗값으로 쓰이기도 합니다. 가끔 필요한데 정확히 입력하기 번거로워서 둘 다 여기서 제공합니다.

참고: 버전 4 UUID는 Math.random이 아니라 브라우저의 암호학적 난수 생성원에서 만들어지므로 식별자로 써도 안전합니다. 버전 7에는 밀리초 단위 타임스탬프가 들어 있어 정렬이 잘 되지만, 그 때문에 대략 언제 만들어졌는지도 드러납니다. 그것이 문제가 되는 곳에는 v7을 쓰지 마세요.

내 웹사이트에 이 도구 넣기

블로그, 수업 페이지, 도움말 글 어디에나 무료로 넣을 수 있습니다. 코드 한 줄만 붙여 넣으면 방문자가 페이지에서 바로 사용할 수 있습니다.