💡 Key Takeaways
- What Base64 Actually Does (And Doesn't Do)
- When Base64 Is Actually the Right Choice
- The Performance Cost Nobody Talks About
- Security Misconceptions That Lead to Disasters
삼 년 전, 나는 내 팀의 주니어 개발자가 전체 50MB 비디오 파일을 Base64로 인코딩하고 이를 JSON API 응답에 직접 삽입하는 것을 보았다. 애플리케이션이 멈춰버렸다. 사용자들은 1분 동안의 로드 시간에 대해 불만을 토로했다. 우리의 CDN 비용은 하룻밤 사이에 세 배로 증가했다. 내가 그에게 왜 그랬는지 물었더니, 그는 "Base64가 인터넷을 통해 안전하게 데이터를 전송할 수 있게 한다고 읽었다"고 대답했다.
💡 주요 요점
- Base64가 실제로 하는 것 (그리고 하지 않는 것)
- Base64가 실제로 올바른 선택인 경우
- 누구도 언급하지 않는 성능 비용
- 재난으로 이어지는 보안 오해
그는 완전히 틀리지 않았다 - 하지만 그 또한 옳지는 않았다. 그 사건은 우리에게 약 12,000달러의 긴급 인프라 확장 비용과 약 200시간의 개발자 시간을 재구성하는 비용을 초래했다. 이 사건은 또한 나에게 중요한 것을 가르쳐 주었다: Base64 인코딩은 겉보기에는 간단해 보이지만 실제로는 매우 오해받는 기술 중 하나이다.
나는 마커스 첸이며, 지난 14년 동안 데이터 집약적인 애플리케이션을 구축해왔다. 처음에는 매일 수백만 건의 거래를 처리하는 금융 서비스 회사에서, 그 다음에는 민감한 환자 데이터를 다루는 의료 스타트업에서, 현재는 50,000개 이상의 비즈니스를 제공하는 SaaS 회사에서 수석 엔지니어로 일하고 있다. 그동안 나는 같은 코드베이스에서 Base64가 훌륭하고 끔찍하게 사용되는 것을 많이 보았다.
이 기사는 기록을 바로잡기 위한 시도이다. Base64가 실제로 무엇을 하고, 언제 그 작업에 적합한 도구인지, 언제 전혀 그렇지 않은지, 그리고 애플리케이션이 열화하고 있을 때 새벽 3시에 되돌아와 당신을 괴롭히지 않을 정보에 기반한 결정을 내리는 방법을 설명하겠다.
Base64가 실제로 하는 것 (그리고 하지 않는 것)
기본부터 시작하자. 대부분의 Base64 오용이 무엇인지에 대한 기본적인 오해로부터 비롯된다는 것을 알았다.
Base64는 64개의 인쇄 가능한 문자(A-Z, a-z, 0-9, +, /)를 사용하여 이진 데이터를 ASCII 텍스트로 변환하는 인코딩 방식이다. 그게 전부다. 이것은 암호화가 아니다. 압축도 아니다. 보안 조치도 아니다. 이것은 번역 메커니즘이다 - 프랑스어에서 영어로 책을 번역하는 것과 같다. 내용은 변하지 않는다; 오직 표현만 변한다.
뒤에서 무슨 일이 일어나는지 살펴보자: Base64는 입력 데이터의 세 바이트(24비트)를 가져와 이를 네 개의 ASCII 문자(32비트)로 표현한다. 이는 인코딩 후 데이터가 대략 33% 증가함을 의미한다. 1MB 파일은 대략 1.33MB가 된다. 100MB 데이터베이스 백업은 133MB가 된다. 이 오버헤드는 사소한 것이 아니며, 사람들은 Base64를 사용할 때 가장 먼저 잊는 것이다.
Base64의 존재 이유는 역사적이다. 인터넷 초창기에는 많은 시스템이 7비트 ASCII 텍스트만 안정적으로 처리할 수 있었다. 이진 데이터 - 이미지, 실행 파일, 압축 파일 - 는 이메일 서버를 통해 전송되거나 텍스트를 위해 설계된 데이터베이스에 저장되거나 일부 바이트 값을 제어 문자로 해석하는 시스템을 통과하면 손상된다. Base64는 이 문제를 해결하여 이진 데이터가 일반 텍스트처럼 가장할 수 있게 하고 이 여정을 무사히 통과할 수 있도록 했다.
나는 2012년에 127보다 값이 큰 바이트를 포함하는 모든 메시지를 조용히 손상시키는 레거시 이메일 시스템에서 작업했던 기억이 난다. 우리는 파이프라인을 통과시키기 위해 모든 첨부파일을 Base64로 인코딩해야 했다. 하지만: 대부분의 현대 시스템은 이제 이러한 제한이 없다. HTTP는 이진 데이터를 잘 처리할 수 있다. 현대 데이터베이스에는 BLOB 유형이 있다. 파일 시스템은 데이터가 텍스트인지 이진인지 신경 쓰지 않는다.
그럼에도 불구하고 개발자들은 여전히 1996년에 살고 있는 것처럼 Base64를 사용하고 있다. 왜일까? 그것이 쉽고, 친숙하며, 작동하는 것처럼 보이기 때문이다 - 작동하지 않을 때까지.
Base64가 실제로 올바른 선택인 경우
내가 하는 경고에도 불구하고 Base64는 본질적으로 나쁜 것이 아니다. 그것이 정확히 올바른 도구인 합법적이고 합리적인 시나리오가 있다. 그것들을 살펴보자.
"Base64는 번역 메커니즘이지 보안 조치가 아니다. 그것을 암호화로 다루는 것은 언어 번역가가 당신의 비밀을 안전하게 만든다고 생각하는 것과 같다 - 그렇지 않다, 단지 다른 알파벳으로 읽을 수 있게 만든다."
가장 일반적인 유효 사용 사례는 텍스트 기반 형식에 작은 이진 자산을 직접 포함하는 것이다. CSS 및 HTML의 데이터 URI가 완벽한 예이다. 애플리케이션의 모든 페이지에 나타나는 2KB 아이콘이 있다면, 이를 Base64 데이터 URI로 포함하는 것은 HTTP 요청을 제거하여 실제로 성능을 향상시킬 수 있다. 계산은 간단하다: HTTP 요청의 오버헤드(기본적으로 DNS 조회, 연결 설정 및 서버 처리 포함 시 50-200ms)는 추가 667바이트(2KB에서 33% 오버헤드)를 전송하는 비용을 초과한다.
나는 이 기술을 중요한 페이지 상단 자산에 대해 광범위하게 사용한다. 한 프로젝트에서는 주요 CSS에 다섯 개의 작은 SVG 아이콘(총 8KB)을 Base64로 인코딩하여 초기 페이지 렌더링 시간을 1.2초에서 0.8초로 줄였다. 추가된 2.6KB 오버헤드는 다섯 개의 개별 HTTP 요청을 제거함으로써 더 크게 상쇄되었다.
또 다른 합법적인 사용 사례는 진정으로 텍스트만 지원하는 시스템에 이진 데이터를 저장하는 것이다. JSON이 명확한 예이다. JSON은 기본적으로 이진 유형이 없으므로 JSON 페이로드에 이진 데이터를 포함해야 할 경우 - 예를 들어, API 응답에 있는 작은 썸네일 이미지 - Base64가 유일한 옵션이다. 그러나 내가 "작은"이라고 언급했음을 주목하라. 나는 엄격한 규칙이 있다: JSON에 포함하기 위해 50KB보다 큰 것은 절대 Base64로 인코딩하지 마라. 그 임계값을 넘어서는 경우, multipart 요청, 별도의 엔드포인트, 또는 직접 이진 프로토콜을 사용해야 한다.
인증 토큰과 암호화 작업도 또 다른 유효한 분야이다. JWT(JSON 웹 토큰)는 헤더 및 페이로드 섹션에 Base64URL 인코딩을 사용한다. 이는 JWT가 HTTP 헤더 및 URL에서 전송될 필요가 있으며, 두 가지 모두 텍스트 기반 맥락이기 때문에 말이 된다. 토큰은 일반적으로 작다(2KB 이하) 및 단순한 문자열로 전달할 수 있는 편의성을 감안할 때 33% 오버헤드는 허용할 수 있다.
나는 URL 안전하고 16진수보다 더 간결한 고유 식별자를 생성할 때도 Base64를 사용한다. 128비트 UUID를 16진수로 인코딩하면 32자이며; 동일한 UUID의 Base64는 단 22자이다. 수백만 개의 ID를 생성하고 데이터베이스 인덱스에 저장하는 경우, 그 31% 공간 절약이 쌓인다. 내가 구축한 시스템에서는 기본 키를 16진수에서 Base64URL 인코딩으로 전환하여 클러스터 전반에 걸쳐 인덱스 크기를 180GB 줄였다.
누구도 언급하지 않는 성능 비용
숫자로 이야기해보자. "성능 오버헤드"에 대한 추상적인 경고는 효과가 없다. 구체적인 측정은 효과가 있다.
| 사용 사례 | Base64를 사용할 때 | Base64를 사용하지 않을 때 | 더 나은 대안 |
|---|---|---|---|
| 작은 이미지 | 5KB 이하 아이콘, CSS/HTML의 인라인 SVG | 사진, 큰 그래픽, 10KB 이상의 무엇이든 | 적절한 캐싱이 가능한 CDN 호스팅 파일 |
| API 응답 | 작은 이진 토큰, 암호화 서명 | 파일 다운로드, 미디어 콘텐츠, 대규모 데이터셋 | 직접 파일 URL 또는 스트리밍 엔드포인트 |
| 이메일 첨부파일 | MIME 인코딩된 첨부파일 (표준 프로토콜) | 파일 크기 제한을 우회하기 위한 수단으로 사용하면 안됨 | 파일 공유 서비스, 클라우드 스토리지 링크 |
| 데이터베이스 저장 | 텍스트 전용 레거시 시스템에 작은 이진 데이터 | 이미지, 문서, 1KB 이상의 어떤 파일 | BLOB 열 또는 별도의 파일 저장소 |
| 데이터 URL | HTTP 요청 수를 줄이기 위한 작은 자산 | 잦은 변경이 있거나 큰 모든 것 | 별도의 캐시 가능 리소스 |
나는 전형적인 애플리케이션 서버(4코어 Intel Xeon, 16GB RAM)에서 다양한 파일 크기를 인코딩하고 디코딩하는 일련의 벤치마크를 진행했다. 10MB 파일을 Base64로 인코딩하는 데 평균 42밀리초가 걸렸다. 이를 다시 디코딩하는 데는 38밀리초가 소요되었다. 듣기에는 많지 않은 것 같지만, 생각해보라: 사용자가 업로드한 이미지를 매 요청마다 인코딩하는 경우, 초당 100개의 요청을 처리한다면 매 초마다 Base64 인코딩에 4.2초의 CPU 시간을 소비하게 된다. 이는 인코딩 오버헤드에 전적으로 전념하는 전체 CPU 코어 하나 이상의 시간이다.
메모리 영향은 더 나쁘다. Base64 인코딩은 전체 입력 및 출력을 메모리에서 동시에 버퍼링해야 하므로, 10MB 파일을 인코딩하기 위해서는 실제로 약 23MB의 메모리가 필요하다.