티스토리 뷰

기술 스택/Etc

UUID 적용하기

github.com/zlrloy 2025. 4. 25. 17:33

만약 엔드포인트가 www.example.com/items/{itemId} 라고 해보자.
/items/1, /items/2, /items/3 … 이런식으로 순차적인 숫자 ID가 붙는다면??

누구나 다음 아이템의 ID를 쉽게 추측하고 접근할 수 있을 것이다.

예측 가능한 숫자형 ID는 크롤링 대상이 되기 쉽다. 우리가 모르는 사이 누군가 수많은 URL을 순회하며 민감한 데이터를 수집하거나 무단 접근을 시도할 수 있다.

이를 방지하기 위해 ID를 무작위 문자열로 바꾸기로 했다. UUID나 nanoid 등과 같은 랜덤 ID를 사용하면 URL을 예측하기 어려워 크롤링 시도를 차단하고 무단 접근을 막을 수 있다.

 

 

1️⃣ UUID(Universally Unique Identifier)란?

UUID는 쉽게 말해 유일한 값을 만들어내는 고유 식별자이다.

128비트(16바이트)로 구성되었고 하이픈(-)으로 구분된 32개의 숫자 문자열이 5개 단위로 나눠져 있다.

#   8자리-4자리-4자리-4자리-12자리
2q5n14bd-3495-4a91-b28r-ae05f245a76f

 

구조

  • 1번째 8자리: time_low, UUID 생성 시점의 하위 32비트 시간 정보
  • 2번째 4자리: time_mid, 시간값의 중간 16비트
  • 3번째 4자리: UUID 버전 정보
  • 4번째 4자리: 변형 정보(대체로 8, 9, a, b 중 하나로 시작)
  • 5번째 12자리: node 식별자

 

 

 

2️⃣ 버전

UUID는 5개의 버전이 있는데 버전 1과 버전 4가 많이 쓰인다.

 

□ UUID v1 - 시간 + MAC 주소 기반으로 UUID 생성
    → 시간순 정렬이 가능하지만 MAC 주소가 노출될 수 있어 프라이버시 이슈가 있다.

☑︎ UUID v4 - 무작위로 랜덤 생성
    → 예측이 불가능해서 v4가 보안성이 높아 자주 사용된다.

    → 대신 저장 공간이 많이 필요하고 인덱싱 속도가 느릴 수 있으니 BINARY(16)로 적용하면 저장 공간을 어느 정도 절약할 수 있다.

 

 

 

3️⃣ UUID 적용

클라이언트가 /items/1로 요청할 경우 → 서버가 DB에서 item_id = 1에 해당하는 UUID 값을 조회 → /items/{uuid} URL로 리다이렉트 → 클라이언트는 UUID URL로 자동 이동

 

1. 기존 ID 정보는 유지 + 별도 UUID 컬럼 추가

-- NULL 허용으로 컬럼 추가
ALTER TABLE items 
ADD COLUMN uuid BINARY(16) UNIQUE;

 

 

 

2. UUID 패키지 설치(JavaScript 기준)

npm install uuid

 

 

 

3. DB 백업(선택)

혹시나 마이그레이션 중 문제가 발생했을 경우를 대비해서 기존 상태로 되돌리기 위한 백업을 추천합니다.

mysqldump -u [사용자명] -p [DB명] > backup.sql

 

 

 

4. 기존 테이블에 마이그레이션으로 uuid 값 채우기

scripts 폴더를 생성 후 update-uuid-v4.js 파일에 아래 코드를 추가한다.

touch .update-uuid-v4.js

 

 

코드 추가

const { v4: uuidv4 } = require('uuid');
const mysql = require('mysql2/promise');

(async () => {
  const connection = await mysql.createConnection({
    host: 'localhost or rds',
    port: 3306,
    user: 'user_name',
    password: 'db_password',
    database: 'db_name',
  });

  const [items] = await connection.query('SELECT id FROM items');
  for (const item of items) {
    const uuid = uuidv4();
    const buffer = Buffer.from(uuid.replace(/-/g, ''), 'hex');
    await connection.query('UPDATE items SET uuid = ? WHERE id = ?', [
      buffer,
      item.id,
    ]);
  }
  await connection.end();
  console.log('모든 데이터의 uuid 컬럼이 v4로 갱신되었습니다.');
})();

 

 

파일 실행

node .update-uuid-v4.js

 

 

콘솔 확인

 

 

기존 파일 삭제

이 파일은 마이그레이션(데이터 변환) 작업을 일회성으로 처리하기 위해 만든 파일이기 때문에 이미 마이그레이션이 성공적으로 끝났고 데이터가 정상적으로 변환되었다면 삭제해도 좋다. (이 파일이 남아 있어도 동작에 아무런 영향이 없음)

 

 

 

5. DB 저장 확인

DB에는 BINARY(16)으로 저장하고 외부 노출(응답, URL 등)에는 BIN_TO_UUID()로 문자열을 변환해서 사용할 수 있다.

 

 

MySQL에서 UUID를 문자열로 조회하는 방법

SELECT id, BIN_TO_UUID(uuid) AS uuid
FROM places
ORDER BY id;

 

 

저장된 uuid를 활용하여 리다이렉트 코드 구현 작업 마무리!

 

 

 

느낀점

처음으로 UUID라는 용어를 배우고 실제 서비스에 적용해보는게 보안을 고려한 첫걸음이였다.
사용자의 정보와 데이터를 다루는 포지션인 만큼 보안과 안정성은 선택이 아니라 필수라는 점을 실감했다.
앞으로는 기능 구현뿐만 아니라 사용자가 안심하고 사용할 수 있는 서비스를 만드는 데에도 더욱 신경 써야겠다고 느꼈다.

 

 

 

 

 

참고
https://inpa.tistory.com/entry/NODE-📚-UUID-모듈?category=914655
https://bbbicb.tistory.com/55
https://kdohyeon.tistory.com/88

https://docs.tosspayments.com/resources/glossary/uuid

 

 

 

Total
Today
Yesterday