Base64
UTF-8 안전 인코딩/디코딩 + URL-safe. 한글도 안 깨짐.

base64 한글 깨짐, 원인과 안전한 해결법 (2026)

btoa로 한글·이모지를 base64로 만들면 왜 깨질까요. 원인과 UTF-8 경유 해결, URL-safe 차이를 정리합니다.

민트빛 배경 위에 'base64 한글 깨짐'이라는 큰 글자와 btoa·UTF-8·URL-safe 카드가 놓인 개발자용 표지 이미지.

btoa('안녕') 한 줄에 빨간 InvalidCharacterError가 뜬 적 있나요. 영문은 멀쩡한데 한글만 넣으면 멈추고, 어디선가 받은 base64를 풀었더니 안녕 같은 글자가 나옵니다. 원인은 함수 하나의 오래된 가정에 있습니다.

btoa가 한글 앞에서 멈추는 이유

브라우저 내장 btoaatob는 한 글자를 1바이트, 즉 0~255 사이의 값으로 가정합니다. 이 범위에 담기는 건 Latin-1 문자뿐입니다.

한글 ‘안’의 코드포인트는 U+C548입니다. 1바이트에 들어가지 않으니 btoa는 받아들이지 못하고 InvalidCharacterError를 던집니다. MDN도 btoa가 Latin-1 범위만 다룬다고 설명합니다. 이모지는 한 글자가 4바이트까지 가므로 더 확실하게 막힙니다.

Latin-1 직접 인코딩과 UTF-8 경유의 차이

같은 입력이라도 처리 경로에 따라 결과가 갈립니다.

입력btoa 직접 호출UTF-8 바이트 경유
Hello성공성공
안녕하세요InvalidCharacterError성공
🌏 (이모지)InvalidCharacterError성공

영문은 어차피 Latin-1 안에 있어 두 경로가 같습니다. 갈라지는 건 한글·이모지처럼 1바이트를 넘는 문자입니다.

해결의 핵심은 UTF-8 바이트로 먼저 바꾸기

방법은 단순합니다. 문자열을 그대로 btoa에 넘기지 말고, TextEncoder로 UTF-8 바이트 배열로 바꾼 뒤 인코딩합니다. 디코딩은 반대로 TextDecoder('utf-8')를 거칩니다. 이러면 모든 문자가 1바이트 단위로 쪼개져 btoa의 가정에 들어맞습니다.

실제로 PiPi Worlds Base64 인코딩 도구안녕하세요 🌏를 넣으면 7JWI64WV7ZWY7IS47JqUIPCfjI8=가 나옵니다. 이 값을 그대로 다시 붙여 넣고 디코딩하면 안녕하세요 🌏가 글자 하나 안 틀리고 돌아옵니다. 도구가 내부에서 UTF-8을 거치기 때문이고, 직접 코드를 짤 때도 같은 원리를 적용하면 됩니다.

표준 base64와 URL-safe의 차이

표준 base64는 +, /, 그리고 끝의 = 패딩을 씁니다. 문제는 이 문자들이 URL이나 파일명 안에서 특수문자로 해석된다는 점입니다.

그래서 URL-safe 변형이 있습니다. +-로, /_로 바꾸고 = 패딩을 떼어 냅니다. 위 예시의 URL-safe 출력은 7JWI64WV7ZWY7IS47JqUIPCfjI8로, 끝 패딩이 사라졌습니다. JWT 토큰의 header·payload 조각이 바로 이 base64url 형식이라, 토큰을 뜯어볼 땐 JWT 디코더가 편합니다. 주소창에 넣을 값 전체를 다뤄야 한다면 URL 인코딩 도구가 따로 있습니다.

붙여넣기 전에: 그 토큰은 어디로 가는가

base64는 암호화가 아닙니다. 누구나 되돌릴 수 있는 인코딩일 뿐입니다. 그래서 운영 환경의 액세스 토큰이나 자격증명을 디코딩할 때, 입력값이 모르는 서버로 전송되는 온라인 도구는 그 자체가 유출 경로가 됩니다.

PiPi Worlds Base64 도구는 인코딩·디코딩이 전부 브라우저 안에서 실행됩니다. 입력은 서버로 전송되지 않으므로 토큰·비공개 조각을 다룰 때도 부담이 없습니다. 디코딩은 표준과 URL-safe 입력을 자동으로 가려내고, 중간에 섞인 공백이나 줄바꿈도 정리해 줍니다. 한글이 깨질 걱정 없이, 받은 값을 그대로 붙여 넣어 확인하세요.

자주 묻는 질문

btoa로 한글을 인코딩하면 왜 오류가 나나요?
브라우저 내장 `btoa`는 한 글자를 1바이트(0~255)로 가정합니다. 한글 '안'은 코드포인트가 U+C548이라 이 범위를 벗어나므로 `InvalidCharacterError`가 발생합니다. 문자열을 UTF-8 바이트로 먼저 바꾼 뒤 인코딩하면 해결됩니다.
디코딩 결과가 '안' 처럼 깨졌어요. 어떻게 복구하나요?
원본 base64 문자열 자체는 멀쩡한데, 디코딩할 때 UTF-8로 해석하지 않아 생기는 현상입니다. 같은 base64 값을 UTF-8 기준으로 디코딩하면 원래 글자가 돌아옵니다. PiPi Worlds Base64 도구는 UTF-8로 디코딩하므로 한글이 그대로 복원됩니다.
표준 base64와 URL-safe는 무엇이 다른가요?
표준은 `+`, `/`, `=` 패딩을 씁니다. URL-safe 변형은 `+`를 `-`로, `/`를 `_`로 바꾸고 끝의 `=` 패딩을 제거합니다. URL 쿼리·JWT 조각·파일명 안에 넣어도 깨지지 않게 하려는 목적입니다.
base64로 만들면 용량이 늘어나나요?
네. Base64는 3바이트를 4개의 ASCII 문자로 표현하므로 출력이 약 33% 커집니다. 바이너리를 텍스트로 안전하게 옮기는 대가입니다.
입력한 텍스트가 서버로 전송되나요?
아니요. PiPi Worlds Base64 도구의 인코딩·디코딩은 모두 브라우저 안에서만 실행되며, 입력값은 서버로 전송되거나 저장되지 않습니다.

Sources

PiFl Labs 콘텐츠팀이 공개 출처를 토대로 작성하고, 발행 전 사내 검수를 거칩니다.

최종 검토:

도구로 돌아가기 →