티스토리 뷰

dev

UUID(범용 고유 식별자)와 RFC4122

IT's me 2021. 3. 26. 23:42

최근 범용 고유 식별자(汎用固有識別子, 영어: universally unique identifier, UUID)를 사용하기 위해서 틈틈히 알아보는 중인데요. 생각보다 구글에서도 원하는 자료를 찾기는 쉽지 않아서 애를 먹는 중입니다. 아니, 자료는 있는데 실제로 적용하기 위한 근거 자료로는 부족하다는 생각이 들어서 자료를 조사하고 있습니다. 

 

일단 원하는 건 불특정 다수 클라이언트에게 키 값을 부여해서 식별하려는 값으로 사용하려는건데요. 중복 체크를 하지 않고 알고리즘으로 중복이 검증되지 않는 이 UUID 스펙을 얼마나 신뢰할 수 있는지 알아보려고 합니다. 

 

범용 고유 식별자(UUID)와 RFC4122

1. UUID란?

 

UUID는 128비트 수입니다. 표준 형식에서 UUID는 32개의 십육진수로 표현되며 총 36개 문자(32개 문자와 4개의 하이픈)로 된 8-4-4-4-12라는 5개의 그룹을 하이픈으로 구분합니다. 예를 들어 하나만 임의로 생성해보자면 아래의 값처럼 표현됩니다.

 

d4bbd032-5e4b-40fb-a2aa-4a646a159d4b

 

이 UUID의 발생 가능한 경우의 수를 따지면 340,282,366,920,938,463,463,374,607,431,768,211,456개가 있는데요. 숫자가 너무 커서 현실감이 떨어지네요. 

 

UUID 레코드 레이아웃이름길이 (바이트)길이 (16진 숫자)내용

time_low  4   8  시간의 low 32비트를 부여하는 정수
time_mid  2   4  시간의 middle 16비트를 부여하는 정수
time_hi_and_version   2   4  최상위 비트에서 4비트 "version", 그리고 시간의 high 12비트

clock_seq_hi_and_res

clock_seq_low

 2   4  최상위 비트에서 1-3비트, 그리고 13-15비트 클럭 시퀀스
node  6   12  48비트 노드 id

 

이 UUID는 국제 인터넷 표준화 기구인 ietf에서 정식 표준으로 채택된 표준 프로토콜이며 rfc4122로 지정되어있습니다. www.ietf.org/rfc/rfc4122.txt

글로벌 표준이라는 말이죠. 


2. UUID 버전

 

UUID 버전에 따라 생성하는 규칙이 다른데요. 1버전부터 5버전까지 있습니다. 

 

  • 버전 1 (datetime and MAC 주소)
  • 버전 2 (datetime and mac + DCE 보안)
  • 버전 3 ( namespace + MD5 해시)
  • 버전 4 (랜덤)
  • 버전 5 ( namespace + SHA-1 해시)

 

 

중요한 건 디바이스 mac 주소를 이용한 버전 1과 순수 랜덤 난수로 발생시킨 버전 4가 많이 사용되는데 버전 1의 경우 MAC 값으로만 사용되는 것이 아니라 환경에 따라 적절하게 맞는 기기의 ID를 사용한다는 점입니다. 

 

mac 주소로 사용하는 아이디같은 경우 플랫폼에 따라서 android id, os id 로 맞게끔 변경해서 처리 합니다. 

 


3. 중복, 충돌 가능성?

 

값의 충돌은 동일한 UUID가 두 번 이상 생성되어 다른 참조에게 할당 될 때 발생합니다. 네트워크 카드에서 고유 한 MAC 주소를 사용하는 표준 버전 1 및 버전 2 UUID의 경우 구현이 실수로 또는 의도적으로 표준과 다른 경우에만 충돌이 발생할 수 있습니다. 

 

버전 1 및 2, 임의로 생성 된 노드 ID, 해시 기반 버전 3 및 버전 5 UUID 및 임의 버전 4 UUID를 사용하는 UUID와 달리 구현 문제 없이도 충돌이 발생할 수 있지만 일반적으로 무시할 수 있을 정도의 확률입니다.

 

예를 들어, 적어도 하나의 충돌의 50 % 확률을 갖기 위해 생성되어야하는 UUID v4의 수는 다음과 같이 계산되는 2.71 * 10(18승) 입니다.

 

2,710,000,000,000,000,000

 

이 숫자는 약 85 년 동안 초당 10 억 개의 UUID를 생성하는 것과 같습니다. 그러니까 초당 10억개씩 만드는걸 85년을 해야 한번 중복이 날까 말까 한 확률이라는 겁니다. 

 

UUID 당 16 바이트로이 많은 UUID를 포함하는 파일은 약 45 엑사 바이트입니다. 이는 현재 존재하는 가장 큰 데이터베이스보다 수백 페타 바이트에 달하는 크기보다 몇 배 더 큽니다.

 

p  될 충돌을 찾을 확률을 위해 생성되어야하는 최소 버전의 UUID 수는 다음 공식에 의해 계산됩니다.

 

따라서 103조개의 UUID 버전 4 내에서 복제본을 찾을 확률은 10 억분의 1입니다.

 


4. 이 식별자를 사용하는 언어 / 시스템

  • 액션스크립트
  • 아파치 Solr
  • C
  • C++
  • Caché 오브젝트스크립트
  • CakePHP
  • 코코아/카본 (OS X)
  • 코드기어 라드 스튜디오 (델파이/C++빌더)
  • 코드퓨전
  • 커먼 리스프
  • CouchDB
  • D
  • 에펠
  • Erlang
  • 파이어버드 서버
  • 프리 파스칼 & 라자루스 IDE
  • 해스켈
  • Haxe
  • 자바
  • 자바스크립트
  • KohanaPHP
  • Lasso
  • 루아
  • OS X
  • MySQL
  • 닷넷 프레임워크
  • OCaml
  • 오라클 데이터베이스
  • PHP
  • PostgreSQL
  • 프로그레스 오픈에지 ABL
  • 파이썬
  • 레볼루션/RunRev
  • 루비
  • SAP 비즈니스오브젝트 데이터 서비스
  • SQL 서버
  • Tcl
  • 유닉스
  • Openstack

5. UUID v4 생성 스크립트

 

<script>
!function(t,e){"object"==typeof exports && "undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).uuidv4=e()}(this,(function(){"use strict";var t="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto),e=new Uint8Array(16);function n(){if(!t)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return t(e)}for(var o=[],r=0;r<256;++r)o[r]=(r+256).toString(16).substr(1);return function(t,e,r){var u=e&&r||0;"string"==typeof t&&(e="binary"===t?new Array(16):null,t=null);var i=(t=t||{}).random||(t.rng||n)();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,e)for(var d=0;d<16;++d)e[u+d]=i[d];return e||function(t,e){var n=e||0,r=o;return[r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]]].join("")}(i)}}));
</script>


<script>
for(var i = 0; i < 1000 ; i ++){
  document.write(uuidv4() + "<br />");
}
function uuidv4_2() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

console.log(uuidv4_2());
</script>

 

Crypto.getRandomValues() 함수는 암호학적으로 강력한 수준의 임의의(random) 값을 생성합니다. 매개 변수로 제공된 배열은 임의의 숫자로 채워집니다 (암호화의 의미는 무작위입니다).

 

충분한 성능을 보장하기 위해 구현에서는 진정한 난수 생성기(pseudo-random number)를 사용하지 않지만 충분한 엔트로피가있는 값으로 시드 된 의사 난수 생성기를 사용하고 있습니다.

 

사용 된 유사난수 생성기(pseudorandom number generator, PRNG)는 구현마다 다르지만 암호화 용도에 적합합니다. 시스템 수준의 엔트로피 소스처럼 충분한 엔트로피가있는 시드를 사용하려면 구현이 필요합니다.

 

Crypto.getRandomValues() 브라우저 호환성

 

https://github.com/uuidjs/uuid

 

uuidjs/uuid

Generate RFC-compliant UUIDs in JavaScript. Contribute to uuidjs/uuid development by creating an account on GitHub.

github.com

<script src="https://unpkg.com/uuid@latest/dist/umd/uuidv4.min.js"></script>
<script>
  alert(uuidv4());
</script>
<script src="https://cdn.jsdelivr.net/npm/uuid@latest/dist/umd/uuidv4.min.js"></script>
<script>
  alert(uuidv4());
</script>

 

가끔 이렇게 개발적인 포스팅을 하니 저도 나름 개발자라 생각이 드는것 같습니다. 아직 완성된 포스팅이 아니라 틈틈히 보완해야겠습니다. 내용은 거의 위키와 깃헙 uuid를 빼다 박았습니다... 공부의 목적으로 재정리하였습니다.

 

감사합니다. 

 

https://www.ietf.org/rfc/rfc4122.txt

 

https://developer.mozilla.org/ko/docs/Web/API/Crypto/getRandomValues

 

Crypto.getRandomValues()

Crypto.getRandomValues() 함수는 암호학적으로 강력한 수준의 임의의(random) 값을 생성합니다. 매개 변수로 제공된 배열은 임의의 숫자로 채워집니다 (암호화의 의미는 무작위입니다).

developer.mozilla.org

 


댓글
최근에 올라온 글
최근에 달린 댓글