UUID (Universally Unique IDentifier)

2024. 4. 19. 09:29지식&개념

UUID 는 네트워크 상에서 고유성이 보장되는 ID 를 만들기 위한 표준 규약이다.

 


 

왜 UUID 를 ID 로 사용할까? 

 

ID 를 넣을때 auto increment 를 사용해 자동으로 숫자가 올라가는 방식으로 사용하는 경우가 있다. ex) 1, 2, 3, 4

이렇게하더라도 노출이 안되는 부분들도 있겠지만, 예를들어 상세조회나 업데이트, 삭제하기 등을 사용할때 파라미터에 ID 를 넣어 주고받는다. 이때 ID 숫자가 노출되는데 이는 유추할수 있어 보안상의 위험을 초래한다.

 

UUID 에는 여러가지 버전이 있는데 그 중에서 많이 사용하는 1, 4 버전에 대해 알아본다.


 

 

UUID v1

 

UUID 는 공통적으로 128비트의 숫자이며, 32자리의 16진수로 표현된다.

8-4-4-4-12 글자마다 하이픈을 집어넣어 5개의 파트로 구분된다.

 

ex) 57a90ca0-fd7d-11ee-8517-31e52dfb29e3

 

이름 길이(바이트) 길이(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 v1 은 호스트 컴퓨터의 MAC 주소와 현재 날짜 및 시간의 조합 등을 사용해 생성된다.

즉 동일한 컴퓨터에서 동시에 생성하지 않는 한 완전히 고유한 ID 를 얻을 수 있음이 보장된다.

 

하지만 이렇게 보장된 고유성은 익명성을 희생한다. UUID v1 은 시간과 MAC 주소를 가지고 있기 때문에 누군가가 생성된 시간과 장소를 식별할 수 있다. 


UUID v4

 

UUID v4 도 마찬가지로 128비트의 숫자이며 32자리의 16진수로 표현된다.

 

ex) 4df9bf0a-3bdf-4cd2-95bc-f6b8be820939

 

UUID v4 는 훨씬 간단하다. UUID v4 를 구성하는 비트는 고유한 논리 없이 무작위로 생성된다. 이 때문에 UUID 를 보면 소스에 대한 정보를 식별할 수 있는 방법이 없다.

 

그러나 UUID 가 중복될 가능성이 있다. 하지만 이에대해 걱정할 필요는 없다.

가능한 조합의 수가 너무 많기 때문이다. (2^128)

수년동안 매초마다 수조개의 ID 를 생성하지 않는 한 복제본을 생성하는 것은 현재 불가능하다.

 

하지만 중요한 애플리케이션의 경우(은행, 의료) UUID v4 의 충돌을 방지하기 위해 고유성 제약 조건을 추가해야 한다.

 

 


비슷한 UUID v4 만들어보기

 

시간기반 필드와 노드 부분을 제외해 간단하게 uuid v4 를 만들어 본 코드이다.

 

class UUIDGenerator {
  constructor() {}

  // 자리수에 맞게 16진수 생성
  createHex(digit) {
    // 주어진 자릿수에 해당하는 최대 16진수 값을 계산 ex) digit 이 4라면 16^4 - 1 을 계산
    const maxHex = 16 ** digit - 1;

    // 0 부터 maxHex 까지의 랜덤 정수 생성, Math.random() 은 0 이상 1 미만의 랜덤수를 생성하고
    // 이를 maxHex + 1 로 곱하고 Math.floor 를 통해 소수점 아래를 버린다.
    const hex = Math.floor(Math.random() * (maxHex + 1));

    // 생성된 정수를 16진수 문자열로 반환하고, 문자열의 길이가 지정된 자릿수에 미치지 못하면 왼쪽을 0으로 채워 길이를 맞춘다.
    return hex.toString(16).padStart(digit, "0");
  }

  generate() {
    const part1 = this.createHex(8);
    const part2 = this.createHex(4);

    // 4 는 uuid 의 버전을 나타냄
    const part3 = "4" + this.createHex(3);

    // 8, 9, a, b 중 하나를 반환받아 3자리 랜덤 16진수를 추가한다.
    const part4 = this.createVariant() + this.createHex(3);
    const part5 = this.createHex(12);

    let uuid = `${part1}-${part2}-${part3}-${part4}-${part5}`;

    return uuid;
  }

  createVariant() {
    const variants = ["8", "9", "a", "b"];
    const index = Math.floor(Math.random() * 4);
    return variants[index];
  }
}

const uuidGenerator = new UUIDGenerator();
console.log(uuidGenerator.generate());

마무리

 

무엇을 사용할지 모르겠다면 v4 를 일반적으로 선택하는 것이 좋다. 충분히 좋고 충돌가능성은 거의 없다.

하지만 실제로 UUID 가 생성된 날짜와 컴퓨터에 대한 표시를 제공하려면 UUID v1 이 적합하다.

 

마지막으로 일반 ID 와 UUID 에 대해서도 언급하려고 한다.

일반 ID 는 유추할 수 있다는 단점이 있고, UUID 는 이 단점을 보완한다.

그렇다고 UUID 는 완벽하지는 않다. 버전마다 특징이 있고 문제점이 있다.

또 일반 정수형 ID 의 경우는 메모리소비량이 적지만, UUID 는 32자리의 16진수로 표현되기에 메모리소비량이 더욱 많다.

일반적으로 보안과 성능은 반비례한다고 생각한다. 

프로덕트의 요구사항을 고려해 적절히, 효율적으로 사용하고 개선하는 것이 개발자라고 생각한다. 

'지식&개념' 카테고리의 다른 글

자바스크립트의 역사  (0) 2024.04.23
토큰에 대한 고민  (0) 2024.04.22
단방향 데이터 바인딩 양방향 데이터 바인딩  (0) 2024.04.18
Angular vs React vs Vue  (0) 2024.04.16
JWT Token & Session  (0) 2023.12.19