Base64는 암호화가 아닙니다: 실제로 하는 일
Base64는 바이너리를 텍스트로 옮기는 전송용 인코딩이지 보안 수단이 아닙니다. 작동 방식과 쓰이는 곳, 그리고 이를 기밀성으로 착각하는 것이 왜 실제 사고로 이어지는지 정리합니다.
Base64는 임의의 바이너리 데이터를 출력 가능한 ASCII 문자 64개만으로 표현하는 방법입니다. 그것이 일의 전부입니다. 이메일·URL·JSON·XML 속성처럼 텍스트를 나르도록 설계된 탓에 raw 바이트에서 막히는 시스템이 많아 생겨났습니다. Base64는 RFC 4648에 정의돼 있고, 같은 문서가 Base32와 Base16도 규정합니다. 그리고 기밀성과는 전혀 무관합니다. Base64로 가장 흔히 저지르는 실수가 바로 그 반대로 가정하는 것입니다.
인코딩이 작동하는 방식
Base64는 입력을 3바이트씩 읽습니다. 3바이트는 24비트이고, 24는 6비트짜리 네 그룹으로 정확히 나뉩니다. 각 6비트 그룹이 64문자 알파벳의 색인이 되어 출력 문자 4개를 만듭니다. 그래서 입력 3바이트마다 출력 4문자가 되는 고정 4:3 비율입니다.
Input bytes: 0x4D 0x61 0x6E ("Man")
Binary: 01001101 01100001 01101110
Regrouped: 010011 010110 000101 101110
Index: 19 22 5 46
Output chars: T W F u ("TWFu")
표준 알파벳은 A–Z, a–z, 0–9, 그리고 값 62와 63에 해당하는 +와
/입니다. = 문자는 패딩용으로 예약돼 있으며 데이터 값으로는 절대
쓰이지 않습니다.
패딩은 길이가 3의 배수가 아닌 입력을 처리합니다. 마지막 그룹이
1바이트(8비트)뿐이면 12비트로 채워 문자 2개로 내보내고 뒤에 ==를
붙입니다. 2바이트(16비트)이면 문자 3개에 = 하나가 붙습니다. 패딩은
출력 길이를 4의 배수로 유지해, 스트리밍 디코더가 고정 크기 블록 단위로
동작할 수 있게 합니다.
비용은 크기입니다. 3바이트마다 4문자이므로 약 33% 늘어납니다. 1MB 바이너리는 줄바꿈 오버헤드를 빼고도 Base64 텍스트로 대략 1.37MB가 됩니다. 그 오버헤드는 텍스트 전용 채널을 통과하는 대가이며, 그래서 굳이 필요 없는 것을 Base64로 만들지 않는 것입니다.
실제로 쓰이는 곳
Base64는 바이트가 텍스트를 통과해야 하는 곳이라면 어디에나 있습니다.
- MIME 이메일. 원래의 동기였습니다. SMTP는 7비트 프로토콜이었고,
첨부 파일은 8비트 바이너리입니다.
Content-Transfer-Encoding: base64는 PDF가 메일 릴레이를 무사히 통과하는 방법입니다. data:URI. 작은 이미지나 폰트를 CSS나 HTML에 직접 담아 별도 HTTP 요청을 줄입니다. 예를 들어data:image/png;base64,iVBORw0KGgo...같은 형태입니다.- JSON/XML 속 바이너리. JSON에는 바이트 타입이 없습니다. raw 바이트를 실어야 하는 필드, 즉 썸네일·인증서·서명 같은 값은 Base64 문자열로 나릅니다.
- JWT 세그먼트. JWT의 점으로 구분된 세 부분은 각각 JSON(헤더와 페이로드) 또는 raw 서명 바이트의 Base64url입니다.
- HTTP Basic 인증.
Authorization: Basic헤더는base64(username:password)입니다. 주의할 점은 인코딩이지 보호가 아니라는 것입니다. 자세한 내용은 아래에서 다룹니다.
이 모든 경우의 목표는 전송이지 비밀 유지가 아닙니다. 인코딩은 설계상, 그리고 누구에게나 되돌릴 수 있습니다.
base64url 변형
표준 +와 / 문자는 URL에 적대적입니다. +는
application/x-www-form-urlencoded 쿼리 문자열에서 공백으로 해석되고,
/는 경로 구분자입니다. 표준 Base64를 URL에 넣으면 다시 퍼센트
인코딩을 거쳐야 하고, 이는 디버깅하기 어려운 버그를 낳는 이중 인코딩
바로 그 상황입니다.
역시 RFC 4648에 정의된 base64url은 문제의 두 문자를 바꿉니다.
-(마이너스)가 +를, _(언더스코어)가 /를 대신합니다. 둘 다 URL에
안전합니다. 패딩은 보통 완전히 생략되는데, 디코더가 입력을 4로 나눈
나머지로 길이를 복원할 수 있고 = 자체도 일부 맥락에서는 이스케이프가
필요하기 때문입니다.
그래서 JWT가 base64url을 쓰는 것입니다. 토큰은 URL·헤더·쿠키를 타고
다니도록 만들어졌습니다. JWT를 디코딩했는데 +나 /가 있어야 할 자리에
-나 _가 보인다면 base64url을 보고 있는 것이고, 표준 알파벳으로
설정된 디코더는 이를 거부합니다.
Base64는 암호화가 아닙니다
여기가 중요한 부분입니다. Base64는 기밀성도, 무결성도, 인증도 제공하지
않습니다. 키를 쓰지 않습니다. 인코딩된 문자열을 가진 사람은 누구나 함수
호출 한 번과 비밀 재료 0으로 원래 바이트를 그대로 복원합니다.
echo dG9wLXNlY3JldA== | base64 -d는 지구상 어느 머신에서나
top-secret을 출력합니다.
Base64를 "안전을 위한 인코딩"이라 부르거나 자격 증명을 "평문이 아니도록" Base64로 실어 보내는 것은 명백한 보안 결함이며, 실제 코드 리뷰와 침해 사후분석에 꾸준히 등장합니다. HTTP Basic 인증이 대표적 예입니다. 비밀번호가 Base64이고, 그래서 Basic 인증은 TLS 위에서만 허용됩니다. 기밀성은 TLS 계층이 제공하고 Base64는 전혀 제공하지 않습니다. TLS를 걷어내면 자격 증명은 전선 위에서 그대로 읽힙니다.
구분은 명확합니다.
| 속성 | Base64 | 암호화 | 해싱 |
|---|---|---|---|
| 되돌릴 수 있는가 | 예, 손쉽게 | 예, 키가 있으면 | 아니요 |
| 키가 필요한가 | 아니요 | 예 | 아니요 |
| 기밀성을 제공하는가 | 아니요 | 예 | 해당 없음 |
| 목적 | 전송 | 비밀 유지 | 지문 / 검증 |
기밀성이 필요하다면 실제로 비밀로 지키는 키를 쓰는 암호가 필요합니다. AES-GCM, ChaCha20-Poly1305, 또는 KMS의 envelope입니다. 그 암호문도 여전히 raw 바이트이므로, 텍스트 채널로 옮기기 위해 그 뒤에 Base64를 입힐 수는 있습니다. 두 작업은 그 순서로 쌓이며, 하나가 다른 하나를 대신하는 일은 없습니다. 어떤 도구가 무엇을 하는지에 대한 더 넓은 지도는 익혀둘 가치가 있습니다. 해싱·암호화·인코딩의 차이는 이 분야에서 가장 꾸준히 혼동되는 주제 중 하나입니다.
Base64는 어떤 의미로도 난독화가 아닙니다. 공격자를 늦추지 못합니다. 알아보고 디코딩하는 것은 자동입니다. Base64로 "숨긴" 비밀은 누구의 도구든 공짜로 수행하는 두 단계가 더 붙은 평문 비밀일 뿐입니다.
언제 쓰고, 언제 쓰지 않는가
바이너리 데이터가 텍스트만 허용하는 채널을 통과해야 하고 약 33% 크기 비용을 측정했거나 감수한다면 Base64를 쓰세요.
data:URI에 작은 자산을 담아 요청을 한 번 줄일 때.- 바이트(인증서·서명·blob)를 JSON이나 XML 필드에 넣을 때.
- URL이나 헤더용 값을 인코딩할 때. 거기서는 표준 알파벳이 아니라 base64url을 쓰세요.
피해야 할 때.
- 채널이 이미 바이너리를 처리할 때.
multipart/form-data로 POST하거나 바이너리 프로토콜로 스트리밍하는 파일을 Base64로 만들지 마세요. 33%를 헛되이 치르는 셈입니다. - 자산이 클 때. 수 MB 이미지를
data:URI로 인라인하면 HTML이 부풀고, 따로 캐시되지 않으며, 파서를 막습니다. 일반 리소스로 제공하세요. - 무언가를 보호하려 할 때. 대신 암호를 쓰세요.
텍스트를 URL 경로나 쿼리 문자열에 안전하게 넣는 관련 문제, 즉 알파벳도 이스케이프 규칙도 다른 또 하나의 전송 인코딩은 URL 퍼센트 인코딩을 보세요. URL이라는 특정 맥락에서 비슷한 전송 문제를 풉니다.
JWT 페이로드를 살펴보거나 data: URI를 디코딩하거나 Basic 인증 헤더에
실제로 무엇이 담겼는지 확인하는 등 값을 직접 인코딩·디코딩해야 할 때,
우리 Base64 인코더/디코더는 표준과 base64url 알파벳을 모두
브라우저에서 처리하며 서버로 아무것도 보내지 않습니다. 바이트를 텍스트로
옮기기에 알맞은 도구입니다. 그리고 바이트를 비밀로 지키는 수단은 아니며,
애초에 그런 의도로 만들어지지도 않았습니다.