← 프로젝트 회고 · Java
RETROSPECTIVE · 회고

Base64 인코딩 결과에 줄바꿈이 끼어 본인인증이 실패한 이유

Java

본인인증 모듈을 연동하면서 요청 데이터를 암호화한 뒤 Base64로 인코딩해 넘기는 부분이 있었다. 로컬에서는 잘 되는데 특정 서버에서만 "데이터 형식 오류"가 났다. 인코딩 결과를 로그로 찍어보니 문자열 중간중간에 \r\n이 끼어 있었다.

원인: 같은 메서드, 다른 동작

Apache Commons Codec의 Base64.encodeBase64String()은 1.4 버전에서는 76자마다 CRLF를 넣는 MIME 형식(chunked) 으로 결과를 만들고, 1.5부터 줄바꿈 없는 결과로 바뀌었다. 코드에서는 최신 버전을 쓴다고 생각했지만, 서버 클래스패스에는 다른 라이브러리가 끌고 온 구버전 codec이 먼저 올라가 있었다.

  1. 레거시 코드에서 자주 보이는 sun.misc.BASE64Encoder도 76자마다 줄바꿈을 넣는다.
  2. 받는 쪽이 줄바꿈을 허용하지 않는 디코더면 그대로 실패한다.

실제로 로딩된 jar 확인하기

버전이 의심될 때는 추측하지 말고 런타임에 어떤 jar에서 클래스가 올라왔는지 찍어보는 게 빠르다.

System.out.println(
org.apache.commons.codec.binary.Base64.class
.getProtectionDomain().getCodeSource().getLocation());

// 빌드 도구에서 의존성 경로 확인
// mvn dependency:tree -Dincludes=commons-codec

해결

  1. Java 8 이상이면 표준 java.util.Base64.getEncoder()를 쓴다. 줄바꿈이 들어가지 않고, MIME 형식이 필요할 때만 getMimeEncoder()를 명시적으로 고른다.
  2. codec을 계속 써야 한다면 Base64.encodeBase64(bytes, false)처럼 chunked 여부를 인자로 명시한다.
  3. URL 파라미터로 넘기는 값이면 +, /, = 때문에 URL-safe 인코딩이나 URL 인코딩도 함께 확인한다.
String encoded = java.util.Base64.getEncoder().encodeToString(cipherBytes);

배운 점

라이브러리 메서드 이름이 같아도 버전에 따라 계약이 다를 수 있다. 외부 시스템에 넘기는 값은 "길이, 허용 문자" 정도라도 로그에서 한 번 검증해두면 이런 문제를 훨씬 빨리 찾는다.

Gunmo Lee
Base64 인코딩 결과에 줄바꿈이 끼어 본인인증이 실패한 이유 | Gunmo's Dev Life