왜 "그냥 마지막 결과를 캐싱"하는 것이 실제로는 통하지 않는가
당연한 해결책은 마지막으로 성공한 확인을 로컬 파일이나 레지스트리에 기억해두고, 다음번에는 네트워크 호출을 건너뛰는 것이다. 이는 오프라인 문제를 해결하지만 아무것도 검증하지 않는다 — 그것은 텍스트 편집기를 가진 누구나 false에서 true로 바꿀 수 있는 디스크 위의 문자열일 뿐이다. 또한 깔끔하게 만료되지도 않으며(복사된 파일은 두 번째 기기에서 영원히 작동한다), 실제로 마지막으로 언제 검증되었는지도 알려줄 수 없다. 당신은 "오프라인 지원 없음"을 "실제로는 확인이 아닌 오프라인 지원"과 맞바꾼 것이다 — 그 파일은 신뢰되는 것이지, 검증되는 것이 아니다.
왜 진짜 오프라인 검증을 직접 만드는 것이 플래그를 캐싱하는 것보다 훨씬 어려운가
진짜 오프라인 검증이란 앱이 서버에게 묻지 않고도, 오직 그 서버에서만 나올 수 있는 데이터만 사용해서 라이선스가 유효하다는 것을 증명할 수 있어야 한다는 뜻이다. 이를 위해서는 개인/공개 키 쌍(서버가 서명하고, 앱은 공개 키 절반만 가짐), 라이선스 키·기기 ID·앱이 시계와 대조해 확인할 수 있는 만료 시간을 담은 압축된 서명 페이로드, 변조를 감지 가능하게 만드는 방법 — 바이트 하나를 뒤집으면 서명이 반드시 실패해야 함 — 그리고 오래되었지만 서명된 결과를 앱이 다시 온라인으로 연결하도록 강제되기 전까지 얼마나 오래 신뢰할지에 대한 결정이 필요하다. 이 중 어느 것도 특이한 암호학은 아니지만, 이를 올바르게 연결하는 것 — 페이로드를 파싱하기도 전에 서명을 검증하고, 그 안의 모든 클레임을 확인하고, 합리적인 만료 기간을 선택하는 것 — 은 한 번 미묘하게 잘못 만들고 결코 알아차리지 못하기 쉬운 바로 그런 종류의 일이다.
서명된 리스: 서버가 서명하고, 앱은 검증만 한다
이것이 바로 SublimeKeys의 오프라인 검증이 하는 일이다. 모든 activate/verify 호출은 리스(lease)를 반환한다 — 라이선스 키, 기기 ID, 제품 ID, 그리고 7일간 유효한 만료 시간을 담은 작은 Ed25519 서명 토큰이다. 당신의 앱은 이를 로컬에 캐싱하고 당신 자신의 바이너리에 내장된 공개 키로 서명을 확인한다 — 개인 키는 절대 우리 서버를 떠나지 않으므로, 사용자의 디스크에는 유효한 리스로 편집될 수 있는 것이 아무것도 없다. 변조된 리스는 그 내용이 파싱되기도 전에 서명 검증에서 즉시 실패한다. 7일 기간이 지나면 다음 확인은 조용히 온라인으로 전환되어 새로운 리스를 받아오고, 이 주기가 반복된다 — 그래서 완전히 오프라인인 기기는 한 번에 최대 일주일까지 검증 가능한 라이선스 상태를 유지하며, 취소된 라이선스는 기기가 다음번에 재연결될 때 감지된다.
추가하는 방법 — 공식 SDK로 3단계
실제로 얻게 되는 것
당신의 앱은 평범한 날에는 네트워크 호출 없이 마이크로초 단위로 라이선스를 검증하고, 일주일간의 비행기 모드나 잠긴 기업 네트워크에서도 계속 올바르게 작동하며, 그럼에도 기기가 재연결된 후 7일 이내에 취소되거나 환불된 라이선스를 잡아낸다 — 암호학 코드를 단 한 줄도 직접 작성하지 않고, 키 관리 시스템을 호스팅하지 않고, 누군가 결국 편집할 방법을 찾아낼 자체 토큰 형식을 발명하지 않고도 말이다.
실제로 누구를 위한 것인가
출장이 잦은 사용자
컨설턴트, 현장 엔지니어, 노트북이 비행기와 고객사 사이에서 실제로 오프라인 시간을 보내는 모든 사람.
잠긴 기업 네트워크
명시적으로 화이트리스트에 없는 모든 것으로의 아웃바운드 API 호출을 차단하는 방화벽 뒤의 기기.
Python 데스크톱 도구
pip install sublimekeys — 오프라인 검증이 공식 SDK에 내장되어 있다.
Electron 앱
npm install sublimekeys — 동일한 서명된 리스 검증, 네이티브 종속성 없음.
에어갭 / 규제 환경
인터넷에 전혀 닿아서는 안 되고, 가끔씩만 동기화되는 기기.
About
Patrick Chen — Sublimearts.io의 인디 개발자. 출장 중이거나 기업 사용자에게 판매되는 모든 데스크톱 앱이 결국 같은 "인터넷 없음" 벽에 부딪힌다는 것을 깨닫고 SublimeKeys에 오프라인 검증을 만들어 넣었다.
Did you find this helpful?