본문 바로가기
컴퓨터 네트워크

Base64는 왜 쓰는 것일까?

by N.Damgom 2021. 2. 12.


Base64를 처음 들어본다면 이 글을 보길 바란다.

https://effectivesquid.tistory.com/m/entry/Base64-인코딩이란

Base64 인코딩이란?

인코딩이란?  Base64 인코딩에 대해 알아보기전에 먼저 인코딩이란게 무엇인지 간략하게 알아보자. 인코딩(encoding)은 정보의 형태나 형식을 표준화, 보안, 처리 속도 향상, 저장 공간 절약 등을 위

effectivesquid.tistory.com

Jwt provider 내 secret key 인코딩


Jwt를 보다보면 JwtProvider에서 jwt.secret을 base64로 인코딩한다.

왜 base64로 인코딩하는지 이해가 안가서 여러 글들을 찾아봤는데 명쾌하지가 않다. 왜 base64 인코딩을 쓰는지 곰곰히 생각하면서 정리한 결론을 소개한다. 밑에 세줄요약도 있다.

먼저 base64를 쓰지 않는 시나리오를 특수문자가 포함된 문자열 “!!” 을 전송하는 상황을 예로 들어 생각해보자. “!!”이라는 문자가 네트워크상 전송되기 위해서는 바이너리 코드인 010101로 바뀌어야 하는데, 문자를 010101 로 바꾸기 위해서는 어떤 규칙에 따라 바꿔야 한다. 이 규칙을 charset이라고 한다.

다양한 charset

Charset은 iso-8859나 utf와 같은 다양한 charset이 있다. 기본적인 문자 abc는 어떤 charset을 쓰더라도 안전하지만, 특수한 문자들은 바이너리 코드로 바꾸는 규칙이 charset간 다를 수 있다.

다시 “!!” 을 전송하는 시나리오로 돌아가보자. 네트워크 전송은 애플리케이션이 할 수 있는 일이 아니다. 모든 i/o작업은 운영체제에게 부탁해야 한다. 프로그래머는 네트워킹을 위해서 여러 라이브러리를 쓸 수 있고, 웹 프레임워크를 쓰는 경우 네트워킹 라이브러리를 쓰지 않을 수 있다. 하지만 어떤 방법이든 결국 애플리케이션에서 생성된 문자열은 tcp 소켓 라이브러리에게 “문자열” 형태 그대로 넘어가게 된다. 운영체제는 이 문자열을 “알아서” 변환해서 전송하거나 수신한다.

winsock.h의 send() function. 보내는 데이터를 담는 인자가 buf이다. buf의 자료형은 const char * , 문자열이다



네트워크에는 서로 다른 시스템이 존재한다. 다양한 버전의 리눅스가 있을 수도, 윈도우나 맥이 있을 수도 있다. 문자열을 바이너리로 바꾸는 작업을 애플리케이션이 운영체제에게 완전히 위임한다면, 문자를 보낼 때 운영체제간 서로 문자열을 바이너리로 바꾸는 방법이 달라 받는 010101을 측에선 송신측이 보낸 “!!”를 “!!”이 아닌 완전히 다른 문자인 “??”로 매핑시킬 수 있다.

그래서 어떤 문자든 간에 어떤 charset을 쓰든 바꾸는 방법이 동일한 기본 문자 abcd...로 바꾸어서 전송해야 한다. 이것이 base64를 쓰는 이유이다.

Base64를 쓰기 위해서는 !!를 우선 바이너리 코드로 바꾸어야 한다. 이유는 링크된 포스팅을 참고하자. !!를 바이너리 코드로 바꾸는 인코딩을 애플리케이션에서 명시적으로 정하면 된다. 클라이언트 애플리케이션에서도 명시적으로 같은 인코딩 방법을 사용하면 된다. Base64 사용 전에는 !!를 운영체제가 알아서 바이너리 코드로 바꿨다면 사용 후에는 애플리케이션에서 명시적으로 변환할 수 있는 것이다.

정리하자면, !! -> (명시적인 바이트코드 인코딩) -> (base64) -> abc -> (송신측 운영체제의 인코딩)-> 010101 -> (네트워크) -> 010101 ->(수신측 운영체제의 디코딩) -> abc -> (base64)-> (명시적인 바이트코드 디코딩) -> !! 가 된다.

위의 코드를 다시 보자. 바이트 코드 인코딩은 애플리케이션에서 명시적으로 정해야한다. String 의 getByte()는 인코딩을 명시적으로 정하지 않기 때문에 위험하다. 심지어 런타임에 charset이 바뀔 수 있다. 다음 링크와 jdk15 doc을 참고하자.


https://stackoverflow.com/questions/19098211/string-getbytes-in-different-default-charsets/19098332#19098332

String.getBytes() in different default charsets

Is it safe to use String.getBytes() ? What happens when a program runs on different systems with different default charset? I suppose I can get different content byte[]? Is it possible to define

stackoverflow.com


더욱 확산되는 도커와 MSA, 클라우드 환경을 고려한다면, 호스트 OS는 리눅스가 아닐 수도 있다.
secretKey.getByte(); 대신 secretKey.getBytes(StandardCharsets.UTF_8);으로 명시적으로 정해주자.


세 줄 요약:

1. 통신할 때 문자는 os가 알아서 바이너리로 바꾼다.

2. 특수한 문자는 os마다 바꾸는 방법이 다를 수 있다.

3. 애플리케이션에서 안전한 문자로 바꿔서 os에게 주자.

물론 “주로” 바이너리를 문자로 전송하거나 URL Safe 위해 기존의 Base64와 다른 Url-safe Base64 사용되기도 한다.
여러 인코딩 중 base64를 쓰는 이유는 앞서 설명한 것과 같다.