로컬 데이터 암호화 형식과 청크 저장 방식을 바꾼 뒤 새로 저장한 값은 잘 읽혔다. 문제는 이미 기기에 남아 있는 이전 형식이었다. 새 코드가 이를 잘못된 데이터로 보고 초기화하면 사용자는 설정과 차트 도구를 한꺼번에 잃을 수 있었다.
보안 방식을 개선하는 변경도 기존 데이터를 읽는 기간과 실패 정책을 가져야 했다.
형식을 추측하지 않고 버전을 기록했다
새 저장 헤더에 명시적인 형식 버전과 알고리즘 식별 정보를 넣었다. 키나 민감한 파라미터 자체는 기록하지 않았다.
{
"formatVersion": 2,
"cipher": "approved-format-example",
"payload": "...",
"metadata": { "chunks": 3 }
}
이전 형식에는 버전이 없어 구조와 검증 결과로 제한적으로 판별하되, 애매하면 임의 복호화를 반복하지 않았다.
읽을 때 안전하게 한 번 이관했다
구형 데이터를 읽는 데 성공하면 메모리에서 검증한 뒤 새 형식으로 임시 저장하고 다시 읽었다. 모든 검증이 끝난 후에만 기존 데이터를 교체했다.
구형 읽기 -> 평문 구조 검증 -> 신형 암호화
-> 임시 저장 -> 신형 재읽기 검증 -> 활성 포인터 교체
중간에 앱이 종료돼도 구형 원본이 남아 다음 실행에서 다시 시도할 수 있었다.
새 형식으로 저장한 뒤 구버전 앱으로 되돌아갈 가능성도 확인했다. 구버전이 신형 파일을 손상된 데이터로 보고 덮어쓰지 않도록 배포와 롤백 범위를 함께 검토했다. 읽기 호환과 쓰기 호환은 같은 말이 아니었다.
실패 횟수와 복구 경로를 제한했다
잘못된 키나 손상 파일에 여러 방식을 무한히 시도하면 앱 시작이 느려지고 오류 분석도 어려웠다. 형식별 시도 순서를 정하고 실패 분류와 백업 여부를 남겼다.
복구 불가능한 비민감 설정은 안전한 기본값으로 돌아가되 사용자에게 초기화 사실을 알렸다. 서버에서 다시 받을 수 있는 값은 재조회했다.
마이그레이션 완료 여부만 별도 플래그로 믿지 않고 실제 신형 데이터를 읽어 검증했다. 플래그 기록과 데이터 교체 사이에 종료될 수 있기 때문이다. 실행을 반복해도 같은 결과가 되는 멱등성이 중요했다.
보안 변경도 데이터 마이그레이션이었다
알고리즘을 바꾸는 코드만 보면 새 형식의 강도에 집중하기 쉽다. 운영 중에는 이전 데이터의 수명, 롤백, 부분 실패가 같은 무게를 가졌다.
이 작업 뒤 저장 형식을 바꿀 때 읽기 호환 기간과 전환 증거를 먼저 설계한다. 더 안전한 형식으로 가는 과정에서 사용자의 정상 데이터를 잃지 않는 것도 보안의 일부였다.