ToolPal
코드가 보이는 컴퓨터 화면

Base64 인코딩 완벽 해설 — 개념부터 실전 사용법까지

📷 Pixabay / Pexels

Base64 인코딩 완벽 해설 — 개념부터 실전 사용법까지

Base64가 무엇인지, 왜 필요한지, 그리고 실제 개발에서 어떻게 사용하는지 알아보세요. 이메일 첨부, 데이터 URL, API 인증까지 실용적인 예제와 함께.

D작성: Daniel Park2026년 4월 14일6분 소요

개발하다 보면 이상한 문자열을 마주칠 때가 있습니다. SGVsbG8gV29ybGQ= 같은 것들입니다. 이게 뭔지 모르면 그냥 지나치게 되는데, 알고 나면 생각보다 자주 보이는 것들입니다. 이게 바로 Base64 인코딩입니다.

Base64는 알고 나면 별거 없지만, 모르면 계속 당황하게 되는 개념 중 하나입니다. 이번 글에서 한 번 제대로 정리해 드리겠습니다.

Base64가 왜 필요한가

먼저 문제 상황을 이해해야 합니다.

컴퓨터의 모든 데이터는 결국 0과 1로 이루어진 이진 데이터입니다. 이미지 파일, PDF, 음악 파일 — 전부 다 바이트의 연속입니다. 그런데 인터넷이 처음 만들어질 때, 많은 시스템이 텍스트를 기반으로 설계되었습니다. 이메일 프로토콜(SMTP)이 대표적입니다.

이메일 시스템은 본래 영어 텍스트만 주고받도록 설계되었습니다. ASCII 문자 범위, 즉 7비트 문자만 처리할 수 있었습니다. 그런데 여기에 이미지나 문서 파일을 첨부해서 보내야 한다면 어떻게 할까요?

이진 파일을 그냥 SMTP 프로토콜로 전송하면, 중간 서버가 특정 바이트를 줄바꿈으로 해석하거나 제어 문자로 처리하면서 데이터가 손상됩니다. 실제로 이런 문제가 있었습니다.

해결책이 Base64입니다. 이진 데이터를 텍스트 시스템 어디서나 안전하게 처리할 수 있는 64개의 문자만 사용해 표현하는 방식입니다. 64개의 문자는 다음과 같습니다:

  • 대문자 알파벳: A-Z (26개)
  • 소문자 알파벳: a-z (26개)
  • 숫자: 0-9 (10개)
  • 특수문자: +/ (2개)
  • 패딩 문자: =

이 문자들은 사실상 모든 텍스트 시스템에서 안전하게 처리됩니다.

어떻게 작동하는가

알고리즘을 완전히 암기할 필요는 없지만, 큰 그림은 알아두면 나중에 크기가 왜 늘어나는지 이해하는 데 도움이 됩니다.

Base64는 3바이트(24비트)를 한 번에 처리합니다. 24비트를 6비트짜리 4개로 나눕니다. 각 6비트 값(0~63)은 Base64 문자표에서 하나의 문자에 대응됩니다. 결과적으로 3바이트 입력이 4개의 ASCII 문자 출력이 됩니다.

여기서 크기 증가가 발생합니다. 3바이트가 4문자가 되니 33% 늘어납니다. 입력 데이터가 3의 배수가 아니면 = 패딩 문자를 붙여서 맞춥니다.

예를 들어 "Hi"를 인코딩하면:

  • H = 72 = 01001000
  • i = 105 = 01101001
  • 2바이트이므로 1바이트 패딩 필요

결과: SGk=

마지막 =는 패딩입니다. "==" 두 개가 붙으면 입력이 2바이트 모자랐다는 뜻입니다.

실제 사용 사례

이메일 첨부 파일

앞서 말했듯 Base64의 탄생 배경입니다. MIME(Multipurpose Internet Mail Extensions) 표준이 이메일에 Base64 인코딩을 사용하여 이진 파일을 첨부할 수 있게 했습니다. 지금도 이메일 서버들은 내부적으로 이 방식을 씁니다.

실제로 Gmail에서 받은 이메일의 원본을 보면, 첨부 파일 부분이 Content-Transfer-Encoding: base64 헤더와 함께 긴 Base64 문자열로 표현되어 있는 것을 확인할 수 있습니다.

CSS 데이터 URL

이미지를 외부 파일 없이 CSS나 HTML에 직접 삽입할 때 사용합니다.

.icon {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...");
}

작은 아이콘이나 로고를 데이터 URL로 삽입하면 추가 HTTP 요청 없이 이미지를 사용할 수 있습니다. 특히 CSS 스프라이트를 대체하거나, 인라인 SVG가 지원되지 않는 환경에서 유용합니다.

단, 파일 크기가 33% 늘어나므로 큰 이미지에는 적합하지 않습니다. 보통 1-2KB 이하의 작은 이미지에만 씁니다.

JWT (JSON Web Token)

현대 웹 인증에서 광범위하게 사용하는 JWT는 내부적으로 Base64URL 인코딩을 사용합니다. JWT는 점(.)으로 구분된 세 부분으로 구성됩니다:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IuyzveustOyduCIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

각 부분을 Base64URL 디코딩하면 JSON 객체가 나옵니다:

// 헤더
{"alg": "HS256", "typ": "JWT"}

// 페이로드
{"sub": "1234567890", "name": "홍길동", "iat": 1516239022}

여기서 Base64URL은 일반 Base64와 약간 다릅니다. URL에서 문제를 일으키는 +-로, /_로 대체하고 패딩 =를 제거합니다. URL 쿼리 파라미터나 경로에 토큰을 포함할 때 인코딩 문제가 생기지 않기 위해서입니다.

HTTP Basic 인증

HTTP 기본 인증에서 브라우저는 사용자 이름과 비밀번호를 username:password 형식으로 합쳐 Base64 인코딩한 뒤 Authorization 헤더에 넣어 보냅니다:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

이걸 디코딩하면 username:password가 그대로 나옵니다. 즉, Base64는 암호화가 아닙니다. HTTPS 없이 Basic 인증을 쓰면 패킷을 가로채는 것만으로 비밀번호를 알 수 있습니다.

API에서의 이미지 전송

REST API에서 이미지나 파일을 JSON 페이로드와 함께 전송해야 할 때 Base64를 사용하는 경우가 있습니다:

{
  "name": "프로필 사진",
  "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAA..."
}

OpenAI의 Vision API나 Google Cloud Vision API 등 여러 AI API가 이미지를 Base64로 받습니다.

JavaScript에서 사용하기

브라우저에서

브라우저에서는 btoa()atob() 함수를 기본 제공합니다:

// 인코딩 (binary to ASCII)
const encoded = btoa('Hello, World!');
console.log(encoded); // SGVsbG8sIFdvcmxkIQ==

// 디코딩 (ASCII to binary)
const decoded = atob('SGVsbG8sIFdvcmxkIQ==');
console.log(decoded); // Hello, World!

함수 이름이 직관적이지 않습니다. btoa는 "binary to ASCII"의 약자고 atob는 반대입니다. 실제로는 둘 다 문자열을 받고 문자열을 반환합니다.

중요한 주의점: btoa()는 Latin-1 범위(코드 포인트 0-255)의 문자만 처리합니다. 한글이나 한자 같은 다국어 문자는 직접 넣으면 에러가 발생합니다:

btoa('안녕하세요'); // DOMException: The string to be encoded contains characters outside of the Latin1 range.

유니코드 문자열을 인코딩하려면 먼저 URI 인코딩을 해야 합니다:

// 유니코드 문자열 인코딩
function encodeUnicode(str) {
  return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
    return String.fromCharCode('0x' + p1);
  }));
}

// 디코딩
function decodeUnicode(str) {
  return decodeURIComponent(atob(str).split('').map(c => {
    return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
  }).join(''));
}

encodeUnicode('안녕하세요'); // 정상 동작

조금 번거롭지만, 한글이나 이모지를 포함한 문자열을 처리할 때 꼭 필요합니다.

Node.js에서

Node.js에서는 Buffer 클래스를 사용하는 게 더 일반적이고 유니코드 문제도 없습니다:

// 인코딩
const encoded = Buffer.from('안녕하세요').toString('base64');
console.log(encoded); // 7JWI64WV7ZWY7IS47JqU

// 디코딩
const decoded = Buffer.from('7JWI64WV7ZWY7IS47JqU', 'base64').toString('utf-8');
console.log(decoded); // 안녕하세요

Buffer.from()은 기본적으로 UTF-8을 사용하기 때문에 한글, 일본어, 이모지 등 모든 유니코드 문자를 올바르게 처리합니다.

Node.js v16부터는 브라우저처럼 전역에서 atob()btoa()를 직접 쓸 수 있지만, Buffer 방식이 더 안정적이고 유니코드 친화적입니다.

파일을 Base64로 변환하기

브라우저에서 파일 업로드 시 Base64로 변환하는 패턴입니다:

function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
  });
}

// 사용 예시
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const base64 = await fileToBase64(file);
  console.log(base64); // data:image/jpeg;base64,...
});

FileReader.readAsDataURL()은 파일을 data URL 형식으로 읽어 Base64 인코딩까지 한 번에 처리합니다.

주의해야 할 것들

Base64는 암호화가 아닙니다

가장 중요한 오해입니다. Base64 인코딩된 문자열을 보면 뭔가 암호화된 것처럼 보이지만, 그냥 형식 변환입니다. 누구나 Base64 디코더(예: Base64 인코더/디코더)로 즉시 원본을 복원할 수 있습니다.

비밀번호나 민감한 데이터를 "Base64로 인코딩해서 저장하면 안전하겠지"라는 생각은 위험합니다. 보안을 위해서는 bcrypt나 Argon2 같은 실제 해싱 알고리즘을 사용해야 합니다.

JWT도 마찬가지입니다. JWT 페이로드는 Base64URL로 인코딩되어 있을 뿐 암호화되지 않았습니다. JWT의 보안은 서명(Signature) 부분에서 오는 것이지 인코딩에서 오는 게 아닙니다.

크기가 약 33% 늘어납니다

이미 언급했지만 중요하니 다시 강조합니다. 1MB 이미지를 Base64로 인코딩하면 약 1.33MB가 됩니다. 이걸 JSON API 응답에 포함시키면 네트워크 트래픽과 파싱 비용이 모두 늘어납니다.

큰 파일은 멀티파트 폼 데이터나 직접 바이너리 스트림으로 전송하는 게 훨씬 효율적입니다. Base64는 이미 텍스트 기반 포맷(JSON, XML, CSS 등)에 작은 이진 데이터를 포함해야 할 때만 사용하세요.

성능 고려사항

Base64 인코딩과 디코딩은 CPU를 사용합니다. 대용량 파일을 실시간으로 Base64 변환하면 성능 문제가 생길 수 있습니다. 브라우저에서 FileReader를 사용할 때는 비동기로 처리하더라도 메인 스레드 부하가 생길 수 있으므로, 매우 큰 파일은 Web Worker를 고려하세요.

도구 활용

Base64 인코딩과 디코딩을 매번 코드로 작성하기 번거로울 때는 Base64 인코더/디코더 도구를 사용하면 편합니다. 텍스트를 붙여넣거나 파일을 드래그하면 바로 변환해 줍니다. JWT 내용을 확인하거나, API 응답의 Base64 데이터를 빠르게 디코딩할 때 특히 유용합니다.

개발하면서 "이게 Base64인가?"라는 의심이 드는 문자열을 만나면 그냥 넣어보세요. 마지막에 = 패딩이 있거나 A-Z, a-z, 0-9, +, / 문자만으로 이루어진 긴 문자열이라면 Base64일 가능성이 높습니다.

정리

Base64는 복잡한 기술이 아닙니다. 이진 데이터를 텍스트로 안전하게 변환하는 방법일 뿐입니다. 처음에는 낯설지만 개념을 이해하면 왜 JWT가 그런 형태인지, 왜 이메일 첨부가 그렇게 큰지, 왜 CSS 데이터 URL이 그렇게 긴지 자연스럽게 이해됩니다.

핵심만 기억하세요:

  • Base64는 인코딩이지 암호화가 아닙니다
  • 크기가 33% 늘어납니다
  • 유니코드 처리에 주의하세요
  • JavaScript에서는 btoa()/atob() 또는 Node.js Buffer를 사용합니다
  • URL에 넣을 때는 URL-safe Base64(+→-, /→_)를 사용합니다

이 정도 알면 Base64가 나와도 당황하지 않을 수 있습니다.

자주 묻는 질문

D

작성자

Daniel Park

서울에서 활동하는 시니어 프런트엔드 엔지니어. 국내 SaaS 회사들에서 7년간 웹 애플리케이션을 개발하며 개발자 도구, 웹 성능 최적화, 프라이버시 중심 설계에 집중해 왔습니다. JavaScript 생태계 오픈소스 기여자이자 ToolPal 창립자입니다.

더 알아보기

이 글 공유하기

XLinkedIn

관련 글