Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save YangSiJun528/cba337ff4b79c28c6d198551dfd54591 to your computer and use it in GitHub Desktop.

Select an option

Save YangSiJun528/cba337ff4b79c28c6d198551dfd54591 to your computer and use it in GitHub Desktop.
Base64가 있는데 왜 Base62를 써야 하나요?.md & BaseN 인코딩 비교.md

Base64가 있는데 왜 Base62를 써야 하나요?

TL;DR

Base64가 Base62보다 효율적이지만, 사용 환경에 따라 Base64의 특수문자(+, /, =)가 문제를 일으킬 수 있어 Base62를 사용합니다.


진법 표기법 기초

이름 영문 표기 사용 문자
10진수 decimal, base 10 0-9
8진수 octet digits, base 8 0-7
16진수 hexadecimal, base 16 0-9, A-F
62진수 base 62 0-9, A-Z, a-z
64진수 base 64 0-9, A-Z, a-z, +, /, =

정보 압축률 비교

효율성 순위

Binary (256진법) > Base64 (64진법) > Base62 (62진법) > Base36 > Base26 > Base10
인코딩 방식 사용 가능 문자 수 한 글자당 표현 비트 상대적 효율
Binary 256 8 bits 최고
Base64 64 6 bits 높음
Base62 62 ~5.95 bits 중간
Base36 36 ~5.17 bits 보통
Base10 10 ~3.32 bits 낮음

결론

Base64가 Base62보다 정보량이 더 적습니다 (더 효율적입니다).

그렇다면 왜 Base62를 사용할까요?


Base64의 문제점

1. URL에서의 충돌 문제

Base64는 다음 문자를 사용합니다:

  • A-Z, a-z, 0-9 (62개) ✓
  • + ✗ (URL에서 공백으로 해석될 수 있음)
  • / ✗ (경로 구분자와 충돌)
  • = ✗ (쿼리스트링 key=value 구분자와 충돌)

문제 예시

http://example.com/api?key=abc+/=&query=xyz+/=

해석 문제:

  • key=abc+/= 에서 =가 어디까지가 value인지 모호함
  • +가 공백으로 해석될 수 있음
  • /가 경로로 해석될 수 있음

실제 시나리오

// Base64로 인코딩된 데이터를 URL에 포함
const data = btoa("Hello World");  // "SGVsbG8gV29ybGQ="

// URL에 포함하면 문제 발생 가능
http://example.com/api?token=SGVsbG8gV29ybGQ=
                                          ↑ = 문자가 쿼리스트링 파싱 오류 유발

2. 파일명/경로에서의 제약

많은 파일 시스템과 웹 서버에서 특정 문자를 제한합니다:

# 문제가 될 수 있는 Base64 문자들
/tmp/file+name.txt    # + 문자
/tmp/path/to/file.txt # / 문자 (경로 구분자)
file=name.txt         # = 문자

Base64의 탄생 배경

역사적 맥락 (RFC 1341)

1990년대 이전:

  • 대부분의 이메일 시스템은 7-bit ASCII만 안전하게 전송 가능
  • 8-bit 데이터 (이미지, 비ASCII 문자)는 전송 불가 또는 깨짐

문제 상황:

한글 (EUC-KR, 8-bit)
→ 이메일 시스템 (7-bit ASCII만 허용)
→ ✗ 전송 실패 또는 데이터 손실

해결책:

8-bit 데이터
→ Base64 인코딩 (6-bit 청크로 분할, ASCII 문자로 표현)
→ 7-bit 안전 문자열
→ 이메일 전송 ✓
→ Base64 디코딩
→ 원본 복원 ✓

Base64 동작 원리

입력: "Man" (3 bytes = 24 bits)

M        a        n
01001101 01100001 01101110

6-bit 청크로 분할:
010011 010110 000101 101110

Base64 인덱스로 변환:
19     22     5      46

Base64 문자:
T      W      F      u

결과: "TWFu"

Padding (=)의 역할

Base64는 3바이트를 4문자로 변환하므로, 입력이 3의 배수가 아니면 padding이 필요:

"Man" (3 bytes) → "TWFu"     (padding 없음)
"Ma"  (2 bytes) → "TWE="     (padding 1개)
"M"   (1 byte)  → "TQ=="     (padding 2개)

해결책들

1. URL-safe Base64

Base64의 문제 문자를 대체:

원본 Base64 URL-safe Base64
+ -
/ _
= 생략 또는 .

예시:

// 일반 Base64
"Hello+World/Test="

// URL-safe Base64
"Hello-World_Test"  // padding 제거

2. Base62

특수문자를 아예 사용하지 않음:

사용 문자: 0-9, A-Z, a-z (62개)

장점:

  • URL, 파일명, 경로 어디서나 안전
  • 추가 인코딩 불필요
  • 사람이 읽고 입력하기 쉬움

단점:

  • Base64보다 ~3% 정도 길이가 김

3. 기타 Base 인코딩

인코딩 사용 문자 용도
Base36 0-9, A-Z 대소문자 구분 불필요한 환경
Base32 A-Z, 2-7 사람이 입력해야 하는 코드 (Google Authenticator)
Base16 (Hex) 0-9, A-F 디버깅, 색상 코드

실무 사용 가이드

Base64를 사용해야 할 때

이메일 첨부파일 (MIME encoding)

Content-Type: image/png
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAAUA...

JSON/XML 내부 바이너리 데이터

{
  "image": "data:image/png;base64,iVBORw0KGgoAAAA..."
}

HTTP Authorization 헤더

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

데이터베이스에 바이너리 저장 (텍스트 컬럼에)

Base62를 사용해야 할 때

URL 단축 서비스 (bit.ly, goo.gl 등)

https://bit.ly/3kX9fG2
              ↑ Base62 인코딩된 ID

YouTube 영상 ID

https://youtube.com/watch?v=dQw4w9WgXcQ
                              ↑ Base64 유사 (특수문자 제외)

파일명 생성

# 안전한 파일명
upload_kX9fG2mNpQ.jpg

# 문제 있는 파일명 (Base64)
upload_kX9+G2/NpQ=.jpg  # +, /, = 문자 포함

REST API 리소스 ID

GET /api/users/7Bx9mK2pQ
POST /api/posts/nZ8kL4wX

쿠키 값

Set-Cookie: session=aB3dE5fG7hJ9kL; Path=/

URL-safe Base64를 사용해야 할 때

JWT (JSON Web Token)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
↑ header (base64url)              ↑ payload (base64url)           ↑ signature (base64url)

OAuth2 state 파라미터

https://oauth.example.com/authorize?state=xyzABC123-_

실제 예시 코드

1. URL에 데이터 포함하기

// ✗ 잘못된 방법: Base64 직접 사용
const data = { userId: 123, role: 'admin' };
const base64 = btoa(JSON.stringify(data));
// 결과: "eyJ1c2VySWQiOjEyMywicm9sZSI6ImFkbWluIn0="
const url = `https://api.com/verify?token=${base64}`;
// 문제: = 문자 때문에 URL 파싱 오류 가능

// ✓ 올바른 방법 1: URL-safe Base64
const urlSafeBase64 = base64
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=/g, '');
const url = `https://api.com/verify?token=${urlSafeBase64}`;

// ✓ 올바른 방법 2: Base62 라이브러리 사용
const base62 = encodeBase62(data);  // 특수문자 없음
const url = `https://api.com/verify?token=${base62}`;

2. 짧은 URL 생성

import base62

# 데이터베이스 auto-increment ID를 Base62로 인코딩
def create_short_url(db_id):
    short_code = base62.encode(db_id)  # 1234567 → "2BiV"
    return f"https://short.url/{short_code}"

# 복원
def get_original_id(short_code):
    return base62.decode(short_code)  # "2BiV" → 1234567

# 예시
create_short_url(1000000)  # https://short.url/4C92
create_short_url(9999999)  # https://short.url/2Biz

3. 파일명 생성

import base62
import uuid

# ✗ Base64 사용 (문제 있음)
def generate_filename_bad():
    unique_id = base64.b64encode(uuid.uuid4().bytes).decode()
    return f"upload_{unique_id}.jpg"
    # 결과: upload_kX9+G2/NpQ==.jpg  (특수문자 포함)

# ✓ Base62 사용 (안전)
def generate_filename_good():
    unique_num = uuid.uuid4().int
    unique_id = base62.encode(unique_num)
    return f"upload_{unique_id}.jpg"
    # 결과: upload_7Bx9mK2pQ.jpg  (영문자+숫자만)

성능 비교

인코딩 길이 비교

원본 데이터: 1000 bytes (무작위 바이너리)

인코딩 방식 결과 길이 증가율
원본 (Binary) 1000 bytes -
Base64 1336 bytes +33.6%
Base62 1375 bytes +37.5%
Base36 1620 bytes +62.0%
Base16 (Hex) 2000 bytes +100%

결론: Base62는 Base64보다 약 3% 더 길지만, 안전성을 고려하면 합리적인 트레이드오프입니다.


요약

핵심 포인트

  1. Base64가 Base62보다 효율적이다 (정보량 3% 적음)

  2. 하지만 Base64의 특수문자 (+, /, =)가 문제를 일으킨다:

    • URL 쿼리스트링에서 충돌
    • 파일명/경로에서 제약
    • 추가 인코딩 필요
  3. Base64의 원래 목적:

    • 이메일에서 8-bit 데이터를 7-bit ASCII로 안전하게 전송
    • RFC 1341 표준
  4. 사용 가이드:

    • URL/파일명: Base62 또는 URL-safe Base64
    • 이메일/JSON: Base64
    • 사람이 입력: Base32, Base36
    • 짧은 URL: Base62
  5. 필요에 따라 다양한 Base 인코딩을 선택할 수 있다:

    • Base36, Base32, Base26, Base16 등
    • 환경의 제약사항에 맞춰 선택

참고 자료

  • RFC 1341: MIME (Multipurpose Internet Mail Extensions) - Base64 인코딩 정의
  • RFC 4648: The Base16, Base32, and Base64 Data Encodings
  • RFC 4648 Section 5: Base64url (URL-safe Base64)

추가 읽을거리

Base64 인코딩 표

Value Encoding  Value Encoding  Value Encoding  Value Encoding
    0 A            17 R            34 i            51 z
    1 B            18 S            35 j            52 0
    2 C            19 T            36 k            53 1
    3 D            20 U            37 l            54 2
    4 E            21 V            38 m            55 3
    5 F            22 W            39 n            56 4
    6 G            23 X            40 o            57 5
    7 H            24 Y            41 p            58 6
    8 I            25 Z            42 q            59 7
    9 J            26 a            43 r            60 8
   10 K            27 b            44 s            61 9
   11 L            28 c            45 t            62 +
   12 M            29 d            46 u            63 /
   13 N            30 e            47 v
   14 O            31 f            48 w         (pad) =
   15 P            32 g            49 x
   16 Q            33 h            50 y

Base62 문자 집합

0-9  : 0123456789         (10개)
A-Z  : ABCDEFGHIJKLMNOPQRSTUVWXYZ  (26개)
a-z  : abcdefghijklmnopqrstuvwxyz  (26개)
총 62개 (특수문자 없음)

BaseN 인코딩 비교 가이드

Hacker News 토론 종합 정리 (#24389584, #38673392, #36514920)


1. Base64

장점:

  • 모든 프로그래밍 언어 stdlib 지원
  • HTTP/MIME 헤더에 필수 (Basic auth 등)
  • 비트 시프팅으로 빠른 인코딩/디코딩 (O(N))
  • "Schelling point" - 별도 협의 없이 통용되는 표준

단점:

  • +, / 문자가 URL에서 문제
  • 패딩 문자 = 필요

변형:

  • Base64url: -, _ 사용으로 URL 안전

2. Base32

장점:

  • 대소문자 구분 없음 → 파일시스템(Windows/macOS) 친화적
  • 2의 거듭제곱 → 비트 연산 효율적
  • 버킷 분포 우수 (1, 32, 1024, 32768 vs hex의 1, 16, 256, 4096)

단점:

  • stdlib 지원 부족 (Ruby 등 미포함)
  • 여러 변형 존재로 "어떤 Base32인지" 혼란

변형 비교

변형 특징 장점 단점
RFC 4648 표준 호환성 혼동 문자 포함
Crockford I/1/L/O/0 정규화, 체크섬 지원 수동 입력 오류 방지 "전화로 읽기" 같은 드문 상황용이라는 비판, 대소문자 무관이 로그 검색 시 문제
z-base-32 혼동 문자 완전 제거 시각적 명확성 덜 알려짐
Base32H S/5, U/V 혼동 해결 물리적 마모된 라벨 가독성 L/1 혼동 미해결, 대문자 전용

Crockford 비판 (inopinatus):

"사람들은 ID를 직접 타이핑하지 않고, 복사-붙여넣기 한다. 대소문자 무관이 오히려 로그 검색, grep에서 문제."


3. Base58 (Bitcoin)

장점:

  • 특수문자 없음, 패딩 없음
  • 더 컴팩트한 인코딩
  • 체크 심볼로 오류 감지
  • Stripe 스타일 ID에 적합: user_1BzGURpnHGn6oNru84B3Ri

단점:

  • O(N²) 복잡도 - 나눗셈/곱셈 반복 필요
  • 대소문자 구분 필수 → 파일시스템 문제
  • 정수에는 좋지만 임의 바이너리 데이터에는 부적합
  • 대소문자 구분이 시각적 혼란 유발

sedatk 경고:

"Base58은 긴 입력에서 성능이 급격히 저하된다"


4. Base62

장점:

  • URL 친화적 (특수문자 없음)
  • KSUID와 함께 사용: 160비트 K-sortable ID
  • a-z, A-Z, 0-9만 사용

단점:

  • 대소문자 구분 필요
  • 2의 거듭제곱이 아님 → 비트 연산 불가

5. Base36

장점:

  • Python int.to_string(36) 등 기본 지원
  • 특수문자 없음
  • 대소문자 무관하게 사용 가능

단점:

  • Base58/62보다 덜 컴팩트

6. 기타 인코딩

인코딩 특징
Bech32 Bitcoin 주소용, 기계 최적화된 문자 선택, 오류 정정
Open Location Code 23456789CFGHJMPQRVWX - 혼동 문자 완전 배제
Base2048 실험적 고밀도 인코딩
Base85/Ascii85 높은 밀도, 하지만 특수문자 다수

핵심 기술적 트레이드오프

2의 거듭제곱 vs 비-2의 거듭제곱

2의 거듭제곱 (Base32, 64):  O(N) - 비트 시프팅
비-2의 거듭제곱 (Base58):   O(N²) - 나눗셈/곱셈 반복

보안 고려사항

dependenttypes 경고:

"Base32H 참조 구현은 사이드 채널 공격에 취약. 비밀 데이터 인코딩 시 상수 시간 구현 필요."

비속어 필터링 논쟁

  • U 제거로 욕설 방지? → "FCKGW 같은 조합은 여전히 가능, 영어 중심적 발상"

용도별 추천

용도 추천 이유
HTTP 헤더/이메일 Base64 표준, 범용 지원
URL/파일명 Base64url 또는 Base62 특수문자 회피
대소문자 무관 파일시스템 Base32 (Crockford) 대소문자 구분 없음
짧은 사용자 ID Base58/62 + 타입 접두어 user_xxx 형태
물리적 라벨/자산 태그 Base32H 또는 Crockford 마모된 라벨 가독성
고성능 필요 Base32/64 O(N) 복잡도
수동 입력 필요 Crockford + 체크섬 오류 감지
연구 논문/구두 전달 z-base-32 시각적 명확성

밀도 비교

인코딩 효율 (bits/char) 예시 (128bit)
Hex 4 32자
Base32 5 26자
Base36 ~5.17 25자
Base58 ~5.86 22자
Base62 ~5.95 22자
Base64 6 22자 (패딩 제외)
Base85 ~6.41 20자

참고 자료

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment