공식
n바이트 입력에 대해 패딩된 Base64(RFC 4648의 기본값)의 길이는 정확히 다음과 같습니다.
length = 4 × ceil(n / 3)
JWT용 Base64URL처럼 패딩이 없으면 다음과 같습니다.
length = ceil(4n / 3)
두 값은 =의 개수만큼 다르며, 그 개수는 n mod 3에 따라 0, 1, 2 중 하나입니다. =가 어디서 오는지는 패딩 가이드에서 설명합니다.
반대로, 길이가 L인 패딩된 Base64 문자열은 다음 크기로 디코딩됩니다.
bytes = 3 × L / 4 − (number of trailing "=")
따라서 TWFu는 3바이트, TWE=는 2바이트, TQ==는 1바이트입니다. 세기 전에 공백과 줄 바꿈을 제거하세요. Base64 크기 계산기는 줄 바꿈과 Data URI 접두사까지 포함해 양방향으로 계산해 줍니다.
코드로는 다음과 같습니다.
import base64, math, os
for n in [1, 2, 3, 100, 1000]:
data = os.urandom(n)
assert len(base64.b64encode(data)) == 4 * math.ceil(n / 3)
const b64Len = (n) => 4 * Math.ceil(n / 3);
const rawLen = (s) => (s.length * 3) / 4 - (s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0);
b64Len(1000); // 1336
rawLen("TWE="); // 2
증가율이 33%인 이유
1바이트는 8비트입니다. Base64 문자 하나는 64 = 2⁶개 기호 중 하나이므로 6비트의 데이터를 담지만, 8비트 ASCII 바이트로 저장됩니다. 그래서 출력 바이트 하나에는 쓸모 있는 비트가 6개뿐이고, 출력은 입력의 8/6 = 4/3배가 되어야 합니다. 33.3%가 추가되는 셈이며, 이는 넘을 수 없는 하한입니다. 알파벳을 포기하지 않는 한 어떤 Base64 구현도 이보다 나을 수 없습니다. (비트를 다시 묶는 과정은 Base64의 작동 원리에서 단계별로 보여 줍니다.)
작은 입력에서는 출력이 항상 4문자 블록 단위로 나오기 때문에 패딩이 비율을 더 나쁘게 만듭니다. 1바이트는 4문자가 되어 300% 증가합니다. 수백 바이트쯤 되면 패딩은 무시할 만한 수준이 되고 비율은 4/3에 수렴합니다.
더 촘촘한 텍스트 인코딩도 있습니다. Base85는 4바이트를 5문자에 담고(25% 증가), Base91은 그보다 약간 낮습니다. 다만 지원 범위가 좁고, 알파벳에 일부 환경에서 문제를 일으키는 문자가 들어 있습니다. 비교는 Base64와 hex, Base32, Base58, Base85 비교에 있습니다.
줄 바꿈: MIME, PEM, 명령줄 도구
일부 형식은 Base64를 여러 줄로 나누며, 줄 끝 문자도 크기에 포함됩니다.
| 형식 | 줄 길이 | 줄 끝 | 전체 증가율 |
|---|---|---|---|
| 일반 Base64 (RFC 4648) | 줄 바꿈 없음 | 없음 | 33.3% |
| MIME 이메일 (RFC 2045) | 76 | CRLF (2바이트) | 36.8% |
GNU base64, Python encodebytes | 76 | LF (1바이트) | 35.1% |
| PEM 인증서와 키 | 64 | LF | 35.4% |
MIME 수치는 4/3 × 78/76에서 나옵니다. Base64 76자마다 CRLF 2바이트가 더 붙기 때문입니다. L = 4 × ceil(n / 3)일 때, 마지막 줄을 포함해 모든 줄 뒤에 CRLF를 붙인 크기는 다음과 같습니다.
mime_length = L + 2 × ceil(L / 76)
76자짜리 온전한 줄 하나에는 정확히 57바이트의 입력이 담기므로, MIME 인코더는 데이터를 57바이트 단위로 처리합니다. 이메일에 대해서는 이메일 속의 Base64에서 더 다루며, MIME Base64 인코더로 줄 바꿈된 출력을 만들 수 있습니다.
크기 표
위 공식으로 계산하고 Python의 base64 모듈로 확인했습니다.
| 입력 | 패딩된 Base64 | 패딩 없음 | MIME (76 + CRLF) | 증가율 (패딩) |
|---|---|---|---|---|
| 1바이트 | 4 | 2 | 6 | 300% |
| 2바이트 | 4 | 3 | 6 | 100% |
| 3바이트 | 4 | 4 | 6 | 33.3% |
| 10바이트 | 16 | 14 | 18 | 60% |
| 57바이트 | 76 | 76 | 78 | 33.3% |
| 100바이트 | 136 | 134 | 140 | 36% |
| 1,000바이트 | 1,336 | 1,334 | 1,372 | 33.6% |
| 1 KiB (1,024) | 1,368 | 1,366 | 1,404 | 33.6% |
| 1 MB (10⁶) | 1,333,336 | 1,333,334 | 1,368,424 | 33.3% |
| 1 MiB (1,048,576) | 1,398,104 | 1,398,102 | 1,434,898 | 33.3% |
| 10 MiB | 13,981,016 | 13,981,014 | 14,348,938 | 33.3% |
| 25 MB (25 × 10⁶) | 33,333,336 | 33,333,334 | 34,210,530 | 33.3% |
마지막 행은 이메일의 경우입니다. SMTP 크기 제한(SIZE 확장, RFC 1870)은 인코딩을 포함해 전송되는 그대로의 메시지를 세므로, 25 MB 파일은 실제로 약 34.2 MB가 되어 25 MB 서버 제한을 통과하지 못합니다. 일부 메일 서비스는 첨부 파일 기준으로 제한을 설명하기도 하므로, 사용하는 서비스가 어떻게 세는지 확인하세요.
압축의 효과
압축은 두 가지 방식으로 Base64와 맞물리며, 순서가 중요합니다.
양쪽 끝을 모두 제어할 수 있다면 인코딩하기 전에 압축하세요. 압축한 데이터의 Base64는 더 작은 수의 4/3입니다. GPL-3 라이선스 텍스트(35,149바이트)를 Node.js zlib의 gzip 레벨 9로 측정한 결과:
| 처리 순서 | 크기 |
|---|---|
| 원본 텍스트 | 35,149 |
| Base64만 | 46,868 |
| Base64 후 gzip | 17,465 |
| gzip 후 Base64 | 16,124 |
| gzip만 | 12,091 |
Gzip + Base64 도구는 브라우저에서 “gzip 후 Base64” 처리를 합니다.
바이너리 데이터라면 전송 압축이 증가분의 대부분을 되찾아 줍니다. Base64 문자열이 gzip이나 Brotli로 압축된 HTTP 응답에 실려 가면, 압축기가 6비트 문자를 다시 문자당 6비트에 가깝게 줄여 줍니다. 1 MiB 무작위 바이트의 Base64는 1,398,104자로 커졌지만, gzip으로 압축하면 1,053,023바이트(원본보다 0.4% 큼), Brotli로는 1,048,805바이트가 되었습니다. 같은 데이터에 MIME 줄 바꿈을 넣으면 gzip 후 1,088,689바이트였으므로, 압축 후에도 CRLF가 약 3.4%를 차지합니다.
텍스트는 다릅니다. Base64는 압축기가 기대는 반복 패턴을 깨뜨리므로 Base64 텍스트는 원래 텍스트보다 훨씬 덜 압축됩니다. 위 표에서 12,091바이트 대 17,465바이트입니다. Data URI 성능 글에 PNG, JPEG, WOFF2, SVG에 대한 측정값이 있습니다.
URL, 헤더, 쿠키 제한
Base64는 URL, 헤더, 쿠키에 넣는 모든 것을 부풀리며, 셋 모두 제한이 있습니다.
- URL. RFC 9110은 송신자와 수신자가 최소 8,000옥텟의 URI를 지원하도록 권장합니다. 많은 서버가 기본적으로 그 근처에서 멈춥니다. nginx는 요청 줄에 8 KB 헤더 버퍼를 할당하고, Apache의
LimitRequestLine기본값은 8,190바이트입니다. 더 긴 URL은 보통414 URI Too Long으로 실패합니다. Base64URL로는 URL의 나머지 부분을 빼고 대략 6,000바이트의 데이터를 담을 수 있습니다. - 헤더. 같은 서버 버퍼가 헤더 줄마다 적용됩니다.
Authorization: Bearer ...헤더의 긴 JWT와 큰 Basic Auth 자격 증명에서 문제가 됩니다. - 쿠키. RFC 6265는 브라우저가 이름과 속성을 포함해 쿠키 하나당 최소 4,096바이트를 지원하도록 요구합니다. Base64로 인코딩하면 약 3 KB의 데이터에 해당합니다.
Base64 페이로드가 이런 제한에 가까워지면 요청 본문으로 보내거나, 서버에 저장하고 ID를 넘기세요.
바이트 수를 입력하거나 문자열을 붙여넣으면 줄 바꿈 유무에 따른 인코딩 크기와 디코딩 크기를 보여 줍니다.
자주 묻는 질문
Base64는 원본 파일보다 얼마나 커지나요?
몇 바이트를 넘는 데이터라면 약 33.3%입니다. MIME 줄 바꿈(76자와 CRLF)을 넣으면 약 36.8%입니다.
Base64 문자열에서 원래 크기를 계산하려면 어떻게 하나요?
공백을 뺀 길이에 3/4를 곱하고 끝에 있는 =의 개수를 빼세요. 예를 들어 TWE=는 4 × 3/4 − 1 = 2바이트입니다.
1바이트 입력이 4문자가 되는 이유는 무엇인가요?
패딩을 쓰면 Base64는 항상 온전한 4문자 블록으로 출력합니다. 1바이트는 2문자를 채우고 나머지 2문자는 =이므로, 아주 작은 입력은 상대적인 증가율이 훨씬 높습니다.
Base64를 더 작게 만들 수 있나요?
인코딩하기 전에 gzip 등으로 데이터를 압축하고, 받는 쪽이 허용한다면 패딩을 생략하세요. Base64 자체의 비율은 고정되어 있습니다. Base85처럼 더 촘촘한 텍스트 인코딩도 있지만 지원 범위가 좁습니다.