Base64 설명: 6비트 그룹화, ~33% 크기 팽창, 패딩, base64url과 표준의 차이

Base64란 무엇인가 — 그리고 무엇이 아닌가

Base64는 바이너리를 텍스트로 변환하는 인코딩 방식입니다. 임의의 바이너리 데이터를 인쇄 가능한 ASCII 문자열로 변환하여, 사람이 읽을 수 있는 텍스트용으로 설계된 컨텍스트에 안전하게 포함할 수 있게 합니다. Base64는 압축이 아닙니다 — 데이터를 더 크게 만듭니다. 암호화도 아닙니다 — 인코딩된 문자열을 가진 누구나 원래 바이트를 쉽게 복원할 수 있습니다. 이름은 정확히 64개의 문자 알파벳을 사용한다는 사실에서 유래했으며, 2⁶ = 64이기 때문에 각 문자가 입력의 정확히 6비트를 나타낼 수 있습니다.

Base64는 독립적인 표준으로 발명된 것이 아닙니다. 7비트 ASCII만 안정적으로 전송할 수 있는 SMTP 인프라를 통해 바이너리 이메일 첨부 파일을 보내야 하는 필요성에서 생겨났습니다. MIME을 정의하는 RFC 2045(1996년)이 이메일용 인코딩을 표준화했습니다. 10년 후, RFC 4648(2006년)이 base64와 그 변형들 — base32와 base64url 포함 — 을 단일 참조 문서로 통합했습니다. RFC 4648은 오늘날 바이너리-텍스트 인코딩이 필요한 모든 새 프로토콜에서 사용되는 권위 있는 사양으로 남아 있습니다.

6비트 그룹화: 세 개의 입력 바이트가 네 개의 문자가 되는 방법

Base64의 핵심은 간단한 비트 재패킹 연산입니다. 바이너리 데이터는 8비트 바이트 그룹으로 도착합니다. base64는 이 비트들을 6비트 청크로 재그룹화하며, 각각은 64문자 알파벳의 한 문자에 매핑됩니다. 6과 8의 최소공배수는 24이므로, 자연스러운 처리 단위는 3바이트 = 24비트 → 4문자(4 × 6비트)입니다. Man을 구체적인 예시로 들면: 세 바이트는 0x4D, 0x61, 0x6E이고, 비트 시퀀스 01001101 01100001 01101110을 만듭니다. 네 개의 6비트 값으로 재그룹화: 010011(19 → T), 010110(22 → W), 000101(5 → F), 101110(46 → u). 인코딩 결과는 TWFu입니다.

이 3대4 바이트 비율이 크기 팽창의 직접적인 원인입니다. 3개의 입력 바이트마다 실제 바이트 값에 상관없이 출력은 항상 4문자입니다. n바이트 입력에 대해 인코딩된 출력은 ceil(n / 3) × 4문자(패딩 전)로, 출력은 항상 입력보다 33% 큽니다(정확히 4/3배). 1KB 파일은 약 1.37KB로 인코딩되고, 1MB 이미지는 약 1.37MB로 인코딩됩니다.

알파벳: A–Z, a–z, 0–9, +, /

표준 base64 알파벳은 6비트 값 0–63을 다음 순서로 인쇄 가능한 ASCII 문자에 매핑합니다: 값 0–25는 대문자 AZ에, 값 26–51은 소문자 az에, 값 52–61은 숫자 09에, 값 62는 +에, 값 63은 /에 매핑됩니다. 이 순서는 MIME 호환성에 뿌리를 둔 역사적 이유로 숫자보다 문자를 앞에 배치합니다 — 이는 ASCII 숫자 순서와 반대입니다. 마지막 두 값에 +/를 선택한 것은 두 문자 모두 URL에서 특별한 의미를 가지므로 수십 년간 상호 운용성 문제를 야기했습니다.

일반적인 오해는 base64가 문자 집합에 독립적이라는 것입니다. 그렇지 않습니다: 알파벳은 고정된 ASCII입니다. 65문자 집합(64개의 데이터 문자 + 패딩용 =) 외의 문자를 만난 디코더는 사양 컨텍스트에 따라 입력을 거부하거나 건너뛰어야 합니다. RFC 4648은 엄격 모드에서 알파벳 외 문자를 거부할 것을 권장합니다. 등호 =는 데이터 문자가 아닌 센티넬입니다 — 패딩을 표시하며 인코딩된 문자열의 끝 이외에는 절대 나타나지 않아야 합니다.

패딩: 등호가 존재하는 이유와 생략할 수 있는 경우

인코딩이 3바이트씩 처리하기 때문에, 길이가 3으로 나누어지지 않는 입력은 마지막에 불완전한 그룹을 남깁니다. 패딩이 이를 해결합니다: 인코딩된 출력이 항상 4문자의 배수가 되도록 강제하여, 출력 길이만으로 원래 바이트 수를 계산할 수 있게 합니다. 입력에 1개의 나머지 바이트가 있으면 2개의 패딩 문자 ==가 추가됩니다. 입력에 2개의 나머지 바이트가 있으면 1개의 패딩 문자 =가 추가됩니다.

패딩은 다른 방법으로 전체 길이를 알 수 있는 컨텍스트에서는 선택 사항입니다. JSON Web Signature 사양인 RFC 7515는 JWT의 점이 이미 세그먼트를 구분하기 때문에 JWT 구성 요소를 인코딩할 때 = 패딩을 생략하도록 구현에 명시적으로 요구합니다. 따라서 JWT의 base64url 인코딩 값은 =로 끝나지 않습니다. 패딩 복원은 간단합니다: 문자열 길이가 4의 배수가 될 때까지 = 문자를 추가합니다.

Base64url: JWT와 OAuth 토큰에 사용되는 URL 안전 변형

표준 base64의 +/ 문자는 URL 컨텍스트에서 문제가 됩니다. 쿼리 문자열의 +application/x-www-form-urlencoded 인코딩에서 공백으로 해석됩니다. /는 경로 세그먼트 구분자입니다. RFC 4648 섹션 5에 정의된 Base64url+-로, /_로 대체합니다. 이 두 문자는 퍼센트 인코딩 없이 URL에서 안전하게 사용할 수 있습니다. 패딩 =도 base64url 컨텍스트에서는 일반적으로 생략됩니다.

Base64url은 컴팩트하고 URL 안전한 바이너리 표현이 필요한 곳 어디서나 사용됩니다: JWT의 헤더와 페이로드 섹션은 base64url 인코딩된 JSON입니다. OAuth 2.0 인증 코드는 종종 base64url 인코딩된 임의 바이트입니다. PKCE(RFC 7636) 코드 검증기와 챌린지도 base64url을 사용합니다. 데이터 팽창 비율은 표준 base64와 동일합니다 — 정확히 4/3 — 알파벳만 다를 뿐 비트 그룹화 알고리즘은 같습니다.

실제 크기 영향과 base64와 바이너리 중 선택하는 방법

약 33%의 오버헤드가 base64의 주요 실질적 비용입니다. 데이터 URIdata:image/png;base64,...로 HTML이나 CSS에 직접 이미지, 폰트, SVG를 임베드 — 의 트레이드오프는 더 큰 문서 대신 HTTP 왕복을 제거하는 것입니다. 이는 소규모 리소스(일반적으로 4–8 KB 미만)에 유리합니다: 절약된 왕복이 크기 증가를 상회하며, 특히 고지연 연결에서 그러합니다. 더 큰 리소스의 경우 크기 증가로 성능이 저하됩니다. 더 큰 HTML 문서는 파싱에 더 오래 걸리고, 렌더링을 차단하며, 페이지와 별도로 캐시할 수 없습니다.

HTTP 기본 인증은 Authorization: Basic ... 헤더에 base64(사용자명:비밀번호)로 자격 증명을 인코딩합니다. 이것은 보안 조치가 아닙니다 — 사용자명과 비밀번호는 디코딩으로 쉽게 복원할 수 있습니다. 기본 인증은 안전하려면 HTTPS가 필요합니다. base64 인코딩은 HTTP 헤더 사양이 인쇄 가능한 ASCII를 요구하기 때문에만 존재합니다. 페이로드에 민감한 정보가 포함된 경우 base64는 암호화의 대체물이 아닙니다. 기밀 데이터에는 인증된 암호화(예: AES-GCM) 또는 JSON Web Encryption(JWE, RFC 7516)을 사용하세요.