Cheondi
개발 · 보안

WebGL 암호화 저장 구조

WebGL 로컬 저장 데이터를 살펴보며 암호화의 역할과 한계를 처음 정리한 기록입니다.

  • #security
  • #webgl
  • #local-storage

WebGL에서 설정 값을 브라우저 저장소에 넣는 코드를 보다가 개발자 도구에서 내용이 그대로 보인다는 걸 알았다. 파일처럼 앱 안에 숨겨져 있을 거라고 막연히 생각했는데, 사용자는 자신의 브라우저 저장소를 쉽게 열어볼 수 있었다. 처음 든 생각은 “그럼 전부 암호화하면 되겠다”였다.

암호화를 붙이면 읽기 어려워지는 건 맞지만 무엇을 막으려는지 정하지 않으면 안전하다고 말하기 어려웠다. 브라우저에서 복호화해야 한다면 키와 코드도 결국 클라이언트에 전달될 수 있었다.

클라이언트 저장 제외 값의 분류

세션 토큰, 단순 화면 설정, 서버에서 다시 받을 수 있는 캐시를 같은 방식으로 다루면 안 됐다. 가장 안전한 저장은 민감한 값을 아예 클라이언트에 오래 남기지 않는 것이었다.

서버에만 둘 값      : 비밀번호, 장기 비밀키
짧게 유지할 값      : 만료가 짧은 세션 정보
로컬에 둘 수 있는 값: 테마, 차트 표시 옵션, 비민감 캐시

업무 규칙상 저장이 필요한 값은 노출됐을 때 영향과 변조됐을 때 영향을 따로 봤다.

암호화와 무결성의 구분

값을 읽지 못하게 암호화해도 공격자가 암호문을 바꾸는 것은 막지 못할 수 있다. 인증된 암호화 방식은 복호화 과정에서 변조 여부도 확인한다. 직접 조합한 XOR이나 고정 키는 암호화처럼 보여도 보호 효과가 약했다.

public record EncryptedPayload(
    int Version,
    string Nonce,
    string CipherText,
    string Tag);

실제 암호화 구현은 검증된 라이브러리와 서버·클라이언트의 키 관리 정책을 따라야 했다. 이 구조는 저장 형식에 필요한 문맥을 보여주는 예시였다.

클라이언트 코드 내 키의 한계

WebGL 빌드 안에 고정 키를 넣으면 숙련된 사용자가 분석해 찾을 수 있다. 그래서 클라이언트 암호화를 서버 비밀을 지키는 수단처럼 설명하면 안 됐다. 우연한 노출을 줄이고 저장 내용을 바로 읽기 어렵게 하는 효과와, 서버 권한을 보호하는 보안을 구분했다.

중요한 권한 검사는 언제나 서버에서 다시 했다. 로컬 설정이 변조돼도 서버 동작이나 다른 사용자 데이터에 영향을 주지 않도록 경계를 두는 편이 더 중요했다.

전체 데이터 흐름의 보안

암호화 적용 여부만 체크하면 일이 끝나는 줄 알았다. 실제로는 저장 필요성, 키의 위치, 변조 처리, 복호화 실패, 이전 형식 호환까지 이어졌다. 값이 깨졌을 때 앱이 멈추지 않고 안전한 기본값으로 돌아가는지도 봐야 했다.

이 시기에는 깊은 보안 설계를 한 게 아니라 질문을 바꾸는 법을 배웠다. “암호화했나?”보다 “무엇을 누구로부터 보호하며, 실패하면 어떤 영향이 있나?”를 먼저 묻게 됐다. 보안 기능은 버튼처럼 추가하는 것이 아니라 데이터 흐름 전체의 성질이었다.

기술 문서 기반의 책임 경계

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

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

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

다음에 WebGL 암호화 저장 구조 같은 문제를 보면 아래 순서부터 확인하려고 한다.

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

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

공식 참고 자료