[비교] 10분 읽기

[비교] Base64 vs Base64URL vs Base32

세 가지 인코딩, 하나의 RFC. 실제로 무엇이 다른지 — 알파벳, 오버헤드, 가독성, 대소문자 민감성 — 그리고 URL, 파일 이름, 이메일, QR 코드, 사람이 말하는 코드에 맞는 것을 어떻게 고를지.

2026년 4월 | comparison

// 빠른 비교 표

                 Base64          Base64URL        Base32
                 (RFC 4648 §4)   (RFC 4648 §5)    (RFC 4648 §6)
────────────────────────────────────────────────────────────────
Alphabet size    64              64               32
Bits per char    6               6                5
Characters used  A-Z a-z 0-9     A-Z a-z 0-9      A-Z 2-7
                 + /             - _              (+ = for pad)
Padding          = (required)    = (optional)     = (optional)
Case-sensitive   Yes             Yes              No (A = a)
Size overhead    ~33%            ~33%             ~60%
URL-safe         No              Yes              Yes
Filename-safe    No              Yes              Yes
DNS-safe         No              Yes              Yes
Human-readable   Medium          Medium           High
Human-spoken     Painful         Painful          Doable
QR-code friendly OK              OK               Excellent
                 (alphanumeric)  (alphanumeric)   (alphanumeric mode)

// 공통점

세 가지 모두 RFC 4648에 정의되어 있습니다. "밑 N 이진-텍스트 인코딩" 계열을 통합한 2006년의 단일 문서입니다. 이들은 동일한 기반 알고리즘을 공유합니다. 이진 입력을 받아서, 비트를 log₂(알파벳 크기) 크기의 덩어리로 재그룹화하고, 각 덩어리를 문자에 매핑한 뒤, 출력 워드 경계에 맞추기 위해 패딩합니다.

• Base64: 6비트 덩어리 → 3바이트마다 4자(4/3 비율, 약 33% 증가)
• Base32: 5비트 덩어리 → 5바이트마다 8자(8/5 비율, 약 60% 증가)
• Base16(hex): 4비트 덩어리 → 1바이트마다 2자(2/1 비율, 100% 증가)

세 가지 모두 가역적이고 결정론적이며 입력의 모든 바이트를 보존합니다. 이들은 인코딩이며, 압축도 암호화도 아닙니다. 문자열을 가진 사람이라면 누구나 다시 디코딩할 수 있습니다.

// BASE64(표준, §4)를 선택할 때

표준 Base64는 URL이 아닌 모든 텍스트 채널의 기본값입니다. MIME 이메일 본문, PEM으로 감싼 인증서, HTTP Basic Auth, S/MIME, XML-DSIG, 데이터 URI, 대부분의 파일 포맷에서 이진-텍스트 컨테이너가 이를 사용합니다. + / = 문자는 모두 따옴표 속성 값, 이메일 헤더(줄 바꿈된 경우), XML/JSON 문자열 내부에서 안전합니다.

다운스트림 소비자가 임의의 인쇄 가능 ASCII를 받아들이는 텍스트 프로토콜일 때, 특히 RFC 수준의 스펙이 명시적으로 언급할 때(MIME: RFC 2045; PEM: RFC 7468; HTTP Basic Auth: RFC 7617; 데이터 URI: RFC 2397) 표준 Base64를 사용하세요.

  • > 이메일 첨부(MIME base64 전송 인코딩)
  • > PEM 인증서, 키, CRL(-----BEGIN ... -----)
  • > HTTP Basic Authentication 헤더 값
  • > 데이터 URI: data:image/png;base64,...
  • > S/MIME 및 XML-ENC 페이로드
  • > 고전적인 SOAP / XML-DSIG 서명
  • > URL에 들어가지 않는 JSON 문서 내부의 모든 이진 필드

// BASE64URL(§5)을 선택할 때

Base64 출력이 URL, 쿠키 값, 파일 이름, DNS 라벨 등 + / =가 퍼센트 인코딩되어야 할 곳에 닿는 순간 Base64URL로 전환하세요. 같은 64자 알파벳을 사용하되 두 개만 바꾸고(+ → -, / → _) 관례적으로 패딩을 제거합니다.

  • > JWT 토큰 — 헤더, 페이로드, 서명 모두 base64url(RFC 7515)
  • > OAuth 2.0 PKCE code_challenge(RFC 7636)
  • > OpenID Connect state 및 nonce 파라미터
  • > 매직 링크, 초대 토큰, 비밀번호 재설정 토큰
  • > URL에 복사될 수 있는 쿠키 값
  • > 해시에서 파생된 파일 이름 — 파일 이름에 /는 피하세요
  • > DNS 라벨, TXT 레코드 — 하이픈 허용, 슬래시 불가
  • > 콘텐츠 주소 지정 스토리지 키
  • > 임의 바이트에서 생성된 짧은 URL 식별자

// BASE32(§6)를 선택할 때

Base32는 단 32자만 사용합니다. 대문자 A–Z와 숫자 2–7입니다. 크기 오버헤드가 약 60%로 Base64보다 훨씬 나쁘지만, Base64가 따라올 수 없는 매우 구체적인 세 가지 속성을 얻습니다.

대소문자 비민감성. 알파벳은 대문자 전용입니다. 문자열을 읽거나 입력하는 사람이 대소문자를 무시할 수 있습니다. JBSWY3DPjbswy3dp는 동일하게 디코딩됩니다.

혼동되지 않는 문자. 숫자 0, 1, 8, 9는 일반적인 폰트에서 O, I, B, g처럼 보이기 때문에 제외됩니다. 숫자는 2–7만 사용됩니다. 이는 종이나 휴대폰 화면에서 사람이 전사할 때 훨씬 더 신뢰할 수 있게 합니다.

영숫자 모드 QR 코드 호환성. QR 코드에는 ASCII의 부분 집합을 사용해 문자당 5.5비트를 인코딩하는 특별한 "영숫자" 모드가 있습니다. Base32는 그 부분 집합(그리고 패딩) 안에 완전히 들어가므로, QR 인코딩된 Base32 문자열이 QR 인코딩된 Base64 문자열보다 현저히 작습니다.

  • > TOTP / HOTP 시크릿 시드 — Google Authenticator, 1Password, Authy 모두 Base32 사용
  • > Tor .onion v3 주소 — ed25519 키의 56자 Base32 인코딩
  • > 매그넷 링크로 공유되는 BitTorrent info-hash
  • > 지오해시 같은 사람이 공유 가능한 위치 코드
  • > 라이선스 키와 제품 일련번호
  • > 인쇄된 복구 코드(2FA 백업 코드, 월렛 니모닉)
  • > 음성 채널을 통한 DTMF 유사 전사
  • > 대소문자 비민감 저장이 필요한 시스템(DNS 라벨)

// 크기 오버헤드 — 구체적인 예

// Input: a 32-byte SHA-256 hash
// Raw: 0x89abcdef…                             (32 bytes, binary — can't put in text)
// Hex (Base16): 40b2e2…                        (64 chars, 100% overhead)
// Base32:       5ENM4H2TQWMZ3O4OQBJAFY5Q       (56 chars, 75% overhead)
// Base64:       ia+N7/eZtRsPj5TqFoqUlD…        (44 chars, 37% overhead)
// Base64URL:    ia-N7_eZtRsPj5TqFoqUlD…        (43 chars, 34% overhead, no padding)

// Input: a 16-byte UUID
// Hex:       e7a6c1d0-4b7d-4c6c-8e2f-9f1a3e4b5c6d (36 chars incl. dashes)
// Base32:    5WTMDUCLPVGGZDRPTF…                  (26 chars)
// Base64:    56bB0Et9TGyOL58aPktcbQ==             (24 chars)
// Base64URL: 56bB0Et9TGyOL58aPktcbQ               (22 chars, no padding)

// 사람이 읽을 수 있는 정도 벤치마크

여기서 Base32가 빛납니다. 다음을 소리 내어 읽어 보세요:

a+b/c1D2e3F/+g= — Base64. "소문자 a, 플러스, 소문자 b, 슬래시, 소문자 c, 일, 대문자 D, 이, 소문자 e, 삼, 대문자 F, 슬래시, 플러스, 소문자 g, 이퀄." 대소문자만으로도 전사 오류가 발생하기 쉽습니다.

JBSWY3DPEHPK3PXP — Base32. "J-B-S-W-Y, 삼, D-P-E-H-P-K, 삼, P-X-P." 대소문자는 상관없습니다. 0/O 또는 1/l 혼동도 없습니다. 전화로 높은 확신으로 읽어 줄 수 있습니다.

이것이 바로 TOTP가 Base32를 쓰는 이유입니다. 누군가는 QR 코드 폴백 화면에서 시드를 자신의 인증 앱에 직접 입력해야 합니다. Base64의 대소문자 민감성은 끝없는 지원 티켓을 만들어 낼 것입니다.

// QR 코드 크기 비교

QR 코드에는 45자 부분 집합(0–9, A–Z 대문자 전용, 공백, $ % * + - . / :)을 사용해 문자당 5.5비트를 담는 특별한 "영숫자 모드"가 있습니다. 이 부분 집합 바깥의 것은 무엇이든 QR 코드를 "바이트 모드"(문자당 8비트)로 강제 전환시켜 훨씬 큰 QR 코드를 만듭니다.

Base32는 영숫자 부분 집합 안에 완전히 들어갑니다. Base64는 그렇지 않습니다. 소문자와 +/=는 바이트 모드를 강제합니다(사실 +/는 영숫자 집합에 있지만, 어떤 소문자든 바이트 모드를 강제합니다). 이는 동일한 페이로드를 Base32로 인코딩했을 때 더 작은 QR 코드에 맞아 들어간다는 뜻이며, 종종 읽기 쉬운 21×21 QR과 붐비는 33×33 QR의 차이를 만듭니다.

// 디코딩 함정

  • > 대소문자 민감성 — Base64 디코더는 대소문자가 맞지 않는 입력을 거부합니다(SGVsbG8=sgvSbg8=). Base32 디코더는 조회 전에 보통 대문자로 정규화하므로 어떤 대소문자든 허용합니다.
  • > 패딩 — 표준 Base64는 = 패딩을 요구하고, JWT/base64url은 이를 금지하며, Base32는 선택 사항으로 둡니다(RFC 4648 §6). 여러분의 디코더가 기대하는 것을 항상 확인하세요.
  • > 공백 — MIME Base64는 76열에서 CR-LF로 줄 바꿈됩니다. 많은 디코더가 공백을 허용하지만 일부는 그렇지 않습니다. atob()나 그 동등물에 넘기기 전에 제거하세요.
  • > 알파벳 충돌 — Base64를 Base32 디코더에 넣거나 그 반대의 경우, 처음에는 작동하는 것처럼 보입니다. A, B, C는 둘 다에서 유효하기 때문입니다. 그러다가 +=에 부딪히면 조용히 실패합니다.
  • > Crockford Base32는 Stripe ID와 일부 블록체인 시스템에서 사용되는 비-RFC 변형입니다. 다른 알파벳(I, L, O, U 제외)을 사용하며 체크 디짓을 지원합니다. RFC 4648 Base32와 혼동하지 마세요.
  • > Base32 Extended Hex(RFC 4648 §7) — 사전식 정렬 순서를 보존하는 대체 Base32 알파벳. DNSSEC NSEC3 레코드에서 사용됩니다. 표준 Base32와 헷갈리기 쉽습니다.

// 의사 결정 흐름도

Does the output go into a URL, cookie, filename, DNS, JWT, or OAuth flow?
│
├─ Yes  →  Does a human need to type or speak the string?
│         │
│         ├─ Yes  →  Base32 (uppercase, no ambiguous chars)
│         │         e.g., TOTP seeds, recovery codes
│         │
│         └─ No   →  Base64URL (more compact, URL-safe)
│                   e.g., JWT, short tokens, hash-named files
│
└─ No  →  Does the output go into a QR code that must stay tiny?
          │
          ├─ Yes  →  Base32 (fits in QR alphanumeric mode)
          │
          └─ No   →  Standard Base64
                    e.g., email MIME, PEM, HTTP Basic, data URI

// BASE16(HEX)은 왜 안 되는가?

16진수(RFC 4648 §8에서는 Base16이라 부름)는 보편적인 폴백입니다. 모든 셸 도구, 디버거, 프로토콜이 이를 이해합니다. 대소문자 비민감하고, 사람이 읽기 쉽고, 구현하기도 쉽습니다. 하지만 페이로드 크기를 두 배로 만들기 때문에(100% 오버헤드), 작은 고정 길이 식별자에만 사용됩니다. SHA-256 해시(16진수 64자 = 32바이트), UUID(16진수 32자 = 16바이트), MAC 주소, 디버거의 메모리 주소 등입니다.

수십 바이트를 넘는 것은 무엇이든, 16진수의 크기 비용은 전송 경로에서 진짜로 고통스럽습니다. Base64는 16진수보다 50% 작고, Base32는 25% 작습니다. 이것이 Base64가 이메일과 웹 임베드 사용 사례에서 승리하고, 16진수가 디버깅과 해시 표시 시나리오에 남은 이유입니다.

// BASE58 / BASE62 / BASE85는 어떨까?

비-RFC의 밑-N 인코딩은 특정 틈새를 위해 존재합니다:
Base58 — 비트코인 주소, Flickr 사진 ID. 사람의 전사를 쉽게 하기 위해 네 개의 혼동되는 문자(0, O, I, l)와 +/를 제외합니다. 약 37% 오버헤드.
Base62 — URL 단축기, Twitter snowflake ID. 영숫자만(특수 문자 없이) 사용하며 이스케이프 없이 URL에 안전합니다. 약 34% 오버헤드.
Base85 / Ascii85 / Z85 — PostScript, PDF, 오래된 ZeroMQ 프레임. 약 25% 오버헤드(Base64보다 조밀)지만 XML/JSON 이스케이프 지옥을 부를 수 있는 까다로운 문자 선택이 포함되어 있습니다.

이들은 흥미롭지만 RFC 4648 표준은 아닙니다. 공개 프로토콜을 배포한다면 거의 항상 Base64 또는 Base64URL이 더 안전한 기본 선택입니다. 모든 언어의 표준 라이브러리가 이미 이를 지원하기 때문입니다. Base58을 고르면 모든 소비자에게 의존성을 함께 배포하는 셈이 됩니다.

// 나란히 놓고 써보기

Base64 인코더 — URL 안전 토글이 있는 표준 알파벳
Base64URL 인코더 — 패딩이 제거된 URL 안전
Base32 인코더 — RFC 4648 §6 알파벳
Base16(hex) 인코더 — 비교용
Base58 인코더 — 비트코인 스타일의 사람 친화적 알파벳

더 읽어 보기:
Base64란 무엇이며 어떻게 작동하는가?
URL 안전 vs 표준 Base64 — 전체 이야기
UTF-8 및 유니코드를 위한 Base64