본문으로 바로가기
Base64
UTF-8 인코딩/디코딩 + URL-safe. 샘플·비민감 값으로 사용하세요.
블로그

Base64 한글 깨짐: 복원할 수 있는 경우와 없는 경우

한글은 UTF-8 바이트로 변환해야 합니다. 잘못 읽은 바이트는 다시 해석할 수 있지만, 잘리거나 덮어쓴 원문은 Base64만으로 복구하지 못합니다.

비민감 예제로 변환 확인 →
이 글의 3가지 포인트

정정 · 2026년 10월 10일: 복구 한계와 패딩 조건을 보완했습니다.

  1. ①
    한글을 btoa에 바로 넣지 않기 문자열 → UTF-8 바이트 → Base64 순서입니다.
  2. ②
    깨짐과 손실은 다른 문제 바이트가 남아 있어야 다시 읽을 수 있습니다. 잘린 원문은 복구하지 못합니다.
  3. ③
    URL-safe도 받는 쪽 규칙 확인 알파벳 변경과 = 패딩 생략은 별개의 조건입니다.
AI 생성 개념 이미지: 노트에 btoa의 바이트 범위 0~255와 한글 안의 U+C548을 적었습니다. 실제 도구 화면이 아닙니다.

btoa('안녕')는 멈추는데, 받은 Base64는 풀어도 읽을 수 없다면 어디서 달라졌는지부터 나눠 보세요. Base64는 바이트를 옮기는 표현이지, 한글 인코딩을 알아서 찾아 주는 복구 프로그램이 아닙니다.

정정 — 2026년 10월 10일: 이전 글은 “같은 값을 UTF-8로 풀면 원문이 돌아온다”, “영문은 두 경로가 같다”, “URL-safe는 패딩을 뗀다”를 조건 없이 설명했습니다. 복구 가능 조건·ASCII와 Latin-1의 차이·받는 형식의 패딩 조건을 보완했습니다. 실제 화면과 측정 시간을 흉내 낸 카드 등은 본문에서 제외했습니다. 남은 표지는 AI 생성 개념 이미지이며 실제 오류 캡처나 시험 기록이 아닙니다.

먼저 구분하기: 입력 오류, 잘못 읽은 바이트, 이미 잃은 원문

지금 보이는 현상먼저 확인할 것할 수 있는 일
btoa('안녕')에서 오류문자열을 바이트로 바꿨는가TextEncoder로 UTF-8 바이트를 만든 뒤 Base64 인코딩
atob 결과가 한글 대신 다른 문자처럼 보임원본 바이트의 문자 인코딩원래 UTF-8이면 바이트 배열을 UTF-8로 다시 읽기
Base64는 풀리지만 UTF-8 오류텍스트인지, 다른 인코딩·파일인지보내는 쪽의 형식 확인. 이미지·압축 파일에는 전용 도구 사용
값이 잘렸거나 �로 바뀐 뒤 저장됨손상 전 원본이 남아 있는가원본에서 다시 받기. 없는 바이트를 Base64로 복구하지 못함

원래 바이트가 잘렸거나 이미 다른 문자로 덮어써졌다면, 인코딩을 반복해도 잃은 글자를 알아낼 수 없습니다. �가 원문에 실제로 포함된 문자일 수도 있으므로 모양만으로 손상 여부를 단정하지 마세요.

다섯 공개 샘플로 문제 지점 찾기

Base64 도구에서 디코딩을 선택한 뒤 아래 값을 하나씩 넣어 보세요. 모두 이 글에서 만든 비민감 테스트 값입니다.

입력 Base64바이트의 의미이 UTF-8 텍스트 도구의 결과
SGVsbG8=ASCII HelloHello
7JWI64WVUTF-8 안녕안녕
Y2Fmw6k=UTF-8 cafécafé
Y2Fm6Q==Latin-1 café의 바이트UTF-8 텍스트가 아니라는 오류
77u/UTF-8의 U+FEFF 한 문자화면에서는 비어 보일 수 있지만 BOM 보존 안내와 1 코드 단위

btoa는 각 값을 0~255의 바이트로 취급합니다. 한글 안(U+C548)은 그 범위를 넘으므로 오류가 납니다. ASCII인 Hello는 직접 호출과 UTF-8 경유가 같지만, café는 다릅니다. btoa('café')의 Y2Fm6Q==는 UTF-8이 아닙니다. 악센트가 있는 문자까지 “영문이면 괜찮다”고 묶으면 놓치는 경우입니다. MDN의 btoa 설명에서도 문자와 바이트 변환을 구분합니다.

atob는 바이트 값이 들어 있는 문자열을 돌려줍니다. 이것을 바로 읽을 텍스트로 쓰지 말고, 원래 인코딩에 맞는 decoder를 거쳐야 합니다. PiPi 도구는 UTF-8 텍스트만 읽으며 잘못된 UTF-8을 대체 문자로 조용히 바꾸지 않습니다. 다른 문자 인코딩을 자동 추측하는 기능은 없습니다.

작은 브라우저 예제: 한글과 이모지 왕복 확인

다음 코드는 정상적인 짧은 샘플 문자열과 패딩 있는 표준 Base64를 위한 예제입니다. URL-safe 입력 정규화나 파일 복구 코드는 아닙니다.

const text = "안녕하세요 🌏";
const bytes = new TextEncoder().encode(text);
const base64 = btoa(
  Array.from(bytes, byte => String.fromCharCode(byte)).join("")
);
const decodedBytes = Uint8Array.from(atob(base64), char => char.charCodeAt(0));
const restored = new TextDecoder("utf-8", {
  fatal: true,
  ignoreBOM: true
}).decode(decodedBytes);
console.log(base64); // 7JWI64WV7ZWY7IS47JqUIPCfjI8=
console.log(restored === text); // true

이 샘플은 JavaScript 문자열 길이로는 8 코드 단위, UTF-8로는 20바이트 → 28자의 Base64입니다. 화면의 글자수·바이트 수·인코딩 출력 길이는 서로 다른 값입니다.

fatal: true는 잘못된 UTF-8을 오류로 알립니다. ignoreBOM: true는 이름과 달리 시작의 U+FEFF를 출력에 포함합니다. 77u/를 도구에서 풀면 보이지 않아도 복사할 결과에는 그 문자가 남습니다. 자동 BOM 삭제 도구가 아닙니다. Encoding Standard, MDN ignoreBOM.

TextEncoder는 짝 없는 UTF-16 surrogate를 대체 문자로 바꿀 수 있습니다. 이 글의 코드는 그런 입력을 위한 일반 변환기가 아니며, PiPi 도구는 짝 없는 입력을 결과 없이 거절합니다. 원문 손상과 변환 성공을 혼동하지 마세요.

URL-safe와 패딩: 받는 API가 원하는 형식 확인

base64url은 표준 Base64의 +, / 대신 -, _를 쓰는 알파벳입니다. 패딩 생략은 받는 형식의 규칙을 따라야 합니다. “URL-safe니까 =를 지우면 어느 API에서나 된다”는 뜻은 아닙니다. RFC 4648 §3.2·§5.

이 도구의 URL-safe 옵션은 패딩을 생략합니다. 위 샘플은 7JWI64WV7ZWY7IS47JqUIPCfjI8이 됩니다. Decode에서는 URL-safe 알파벳과 빠진 패딩을 정규화하지만, 이 도구가 받아들였다는 이유로 다른 API의 규칙까지 만족한다고 판단하지 마세요. 도구는 Base64 입력의 공백·줄바꿈을 제거하며, 디코딩된 텍스트의 공백과 줄바꿈을 지우는 것은 아닙니다.

JWT의 header·payload 조각을 읽는 것은 서명 검증이나 신뢰성 판정이 아닙니다. 공개 테스트 값만 JWT 디코더에서 살펴보세요. URL에 값을 넣는 문맥과 퍼센트 인코딩은 URL 인코딩 가이드에서 따로 확인할 수 있습니다.

“약 33% 증가”는 글자수가 아닌 바이트 기준

패딩 있는 표준 Base64의 출력 길이는 4 × ceil(입력 바이트 수 / 3) 입니다. ceil은 올림입니다. 긴 입력은 대략 4/3배가 되지만 짧은 입력에는 패딩 비중이 큽니다.

  • Hello: 5바이트 → 8자, 원래보다 60% 증가.
  • 안녕: 6바이트 → 8자, 약 33% 증가. 한글 두 글자를 두 바이트로 세면 안 됩니다.
  • 안녕하세요 🌏: 20바이트 → 28자, 40% 증가.

Base64는 암호화가 아닙니다. 운영 토큰·비밀번호·비공개 JSON·개인정보를 넣지 마세요. 변환 자체가 브라우저에서 실행된다는 설명은 페이지 전체나 브라우저 환경의 비밀 보호를 보증하지 않습니다. 비민감 샘플을 쓰고, 비밀은 승인된 로컬 작업 절차를 따르세요.

자주 묻는 질문

btoa로 한글을 인코딩하면 왜 오류가 나나요?
btoa는 문자열의 각 값을 0~255의 바이트로 취급합니다. 한글 안(U+C548)은 범위를 넘으므로 InvalidCharacterError가 납니다. 정상적인 한글 문자열을 TextEncoder로 UTF-8 바이트로 바꾼 뒤 인코딩하세요.
깨진 한글은 Base64를 다시 풀면 항상 복원되나요?
아닙니다. 원래 UTF-8 바이트가 그대로 있는데 다른 방식으로 읽은 경우에는 올바르게 다시 해석할 수 있습니다. 값이 잘리거나 대체 문자로 덮어써졌다면 Base64만으로 잃어버린 원문을 복구할 수 없습니다. 원본과 전송 경로를 확인하세요.
Base64는 맞는데 UTF-8 오류가 나면 어떻게 하나요?
Base64 문법이 맞아도 내용은 다른 문자 인코딩이나 이미지·압축 파일일 수 있습니다. 이 도구는 UTF-8 텍스트용이며 비텍스트 바이트를 억지로 문자로 바꾸지 않습니다. 보내는 쪽의 형식·문자 인코딩을 확인하고 파일에는 전용 도구를 사용하세요.
URL-safe라면 끝의 =를 무조건 지워도 되나요?
아닙니다. base64url은 +와 / 대신 -와 _를 쓰는 알파벳입니다. 패딩 생략은 받는 형식의 규칙을 따라야 합니다. PiPi의 URL-safe 출력은 패딩을 생략하지만, 다른 API가 같은 정책을 쓴다는 뜻은 아닙니다.
왜 한글 두 글자가 Base64 여덟 글자가 되나요?
안녕은 UTF-8 6바이트이고 패딩 포함 표준 Base64는 8자입니다. 계산 기준은 화면 글자수가 아니라 바이트입니다. 출력 길이는 4 × ceil(입력 바이트 수 / 3)이며 짧은 입력에서는 증가율이 약 33%보다 클 수 있습니다.
입력한 텍스트가 서버로 전송되나요?
Base64 변환 자체는 브라우저에서 실행됩니다. 이것만으로 페이지 전체나 브라우저 환경에서 비밀의 안전을 보장할 수는 없습니다. 운영 토큰·비밀번호·개인정보는 넣지 말고 공개 예제나 비민감 테스트 값만 사용하세요.

출처

검토 기록: Codex AI의 편집·코드 검토(사람 전문가의 감수 아님)

확인 내역과 한계 펼쳐 보기

2026-10-10 16:43 KST에 기존 한국어 운영 원고의 무조건 복원·Latin-1/UTF-8 동일·무패딩 설명과 이미지 alt 불일치를 확인했습니다. MDN btoa·ignoreBOM, WHATWG Encoding Standard, RFC 4648을 대조하고 공개 샘플을 독립 바이트 인코딩 및 본문 코드 실행으로 검산했습니다. 실제 브라우저의 미리보기·운영 검수 결과는 별도 배포 검수 기록으로 구분하며 사람 보안 감사·실제 독서나 성과 증거가 아닙니다. 기존 RFC6750 접근일은 다시 읽지 않아 유지합니다.

이 글에서 더한 것 — 한국어 입력 오류와 바이트 해석 오류를 분리하고, 실제 도구와 독립 브라우저 코드로 대조할 수 있는 다섯 샘플·바이트 길이·복구 불가 조건을 제공합니다. 패딩 정책과 보이지 않는 BOM도 별도로 확인합니다.

검토 기록은 기재된 확인 내역이며, 독립적인 정확성 보증은 아닙니다.

도구로 돌아가기 →