Cheondi
개발 · 보안

64KB 초과 암호화 데이터 처리

WebGL 암호화 저장 데이터가 커지며 드러난 크기 제한과 호환 문제를 다룬 기록입니다.

  • #security
  • #webgl
  • #local-data

WebGL 로컬 설정을 암호화한 뒤 작은 데이터에서는 아무 문제가 없었다. 실제 사용 데이터가 늘자 특정 크기부터 저장은 성공한 것처럼 보이는데 다시 읽으면 뒤가 잘리거나 복호화에 실패했다. 경계가 약 64KB 부근에서 반복돼 처음에는 브라우저 저장소의 용량 제한이라고 생각했다.

하지만 브라우저 저장소 전체 한도는 그보다 훨씬 클 수 있었다. 문제는 당시 사용하던 Unity와 JavaScript 사이 전달·저장 경로의 한 번 처리 크기와 문자열 변환 방식에 있었다. 64KB를 WebGL 전체의 보편적인 제한처럼 보면 원인을 잘못 설명하게 됐다.

암호화 이후의 데이터 크기 증가

원본 JSON을 암호화하면 nonce와 인증 태그 같은 메타데이터가 붙고, 바이너리를 문자열로 저장하기 위해 Base64를 사용하면 크기가 대략 4/3로 늘어난다.

원본 JSON       48KB
암호문·메타데이터 약간 증가
Base64 문자열   약 64KB 이상

평문 크기만 측정하던 검사가 실제 저장 문자열의 경계를 놓치고 있었다. UTF-8 바이트 수와 최종 직렬화 크기를 각각 기록했다.

저장 단계별 크기 측정

암호화 함수, C# 문자열, WebGL 브리지, JavaScript 저장, 다시 읽기 중 어디에서 길이가 달라지는지 확인했다.

LogSize("plain", Encoding.UTF8.GetByteCount(json));
LogSize("encrypted", Encoding.UTF8.GetByteCount(payload));
bridge.Save(key, payload);

로그에는 데이터 내용이나 키를 남기지 않고 크기와 형식 버전, 성공 단계만 기록했다. 60KB, 64KB, 65KB처럼 경계 주변의 생성 데이터로 반복했다.

암호화 데이터의 분할 저장

큰 문자열을 무조건 한 번에 넘기지 않고 헤더와 일정 크기의 청크로 나눴다. 헤더에는 형식 버전, 청크 수, 전체 길이, 무결성 확인값을 넣었다.

{
  "version": 2,
  "chunks": 3,
  "length": 70124,
  "checksum": "example-digest"
}

모든 청크가 검증된 뒤에만 새 데이터를 활성화했다. 중간 저장에 실패하면 이전 정상 데이터를 유지하고 불완전한 청크를 정리했다. 압축은 데이터 특성과 보안 검토 후 별도 선택으로 두었다.

저장 환경별 제한 검증

64KB라는 숫자만 보고 데이터를 줄였으면 다시 크기가 커질 때 같은 문제가 났을 것이다. 어떤 계층의 경계인지 찾고, 최종 저장 크기를 측정하고, 실패를 원자적으로 처리하는 구조가 필요했다.

이 경험 뒤 용량 문제를 만나면 플랫폼의 한도라고 바로 결론 내리지 않는다. 변환 단계마다 크기와 성공 여부를 확인한다. 보안 기능은 암호화 알고리즘뿐 아니라 데이터를 안전하게 전달하고 복구하는 저장 구조까지 포함했다.

기술 문서 기반의 책임 경계

작업 당시에는 눈앞의 오류를 먼저 고쳤지만, 이후 기술 문서와 맞춰 보며 확인 순서를 조금 더 구체화했다.

Web Storage는 origin 단위의 저장 공간을 제공하지만 비밀 저장소를 정의하지는 않는다. 같은 origin에서 실행되는 스크립트는 저장 값에 접근할 수 있으므로, XSS가 가능한 상황에서 암호화된 값도 복호화 직전에는 노출될 수 있다.

Web Cryptography API 역시 검증된 연산을 제공하는 도구이지 키 보관 정책을 자동으로 만들어 주지는 않는다. 알고리즘 이름보다 키의 생성·보관·교체와 복호화 실패 처리를 함께 기록해야 실제 경계가 보인다.

다음에 64KB 초과 암호화 데이터 처리 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 평문 크기와 암호문 크기 제한
  • nonce·tag·version 저장 형식
  • 키 교체와 이전 값 복호화
  • 변조·잘림·저장 공간 부족 처리

서버 권한을 증명하는 장기 비밀은 브라우저 저장을 피하고, 저장이 꼭 필요한 값도 만료와 폐기 경로를 가져야 한다.

공식 참고 자료