"출시하고 나서 붙이면 안 되나요?" — 대부분은 됩니다, 다섯 가지만 빼고
출시를 2주 앞둔 팀에게 보안 이야기를 꺼내면 대체로 이런 답이 돌아옵니다. "지금은 콘텐츠 마무리가 급해서요. 출시하고 반응 보고 붙일게요."
합리적인 판단입니다. 실제로 대부분의 보안 기능은 나중에 추가할 수 있습니다. 탐지 모듈을 켜는 일, 로그를 수집하는 일, 정책을 조이는 일은 라이브 중에도 얼마든지 합니다.
문제는 그렇지 않은 것도 섞여 있다는 점입니다. 몇 가지 결정은 빌드를 제출하는 순간 굳어져서, 나중에 바꾸려면 재출시를 하거나 유저 데이터를 건드려야 합니다. 급한 건 콘텐츠가 맞습니다. 다만 이 다섯 가지는 지금 30분만 확인해 두면 나중에 몇 주를 아낍니다.
이 글은 무엇을 도입할지 고르는 글이 아닙니다. 지금 정해 두지 않으면 나중에 비싸지는 것들만 다룹니다. 팀 규모에 맞춰 무엇부터 도입할지는 인디·소규모 개발사를 위한 보안 도입 가이드에서 따로 다뤘습니다.
1. 스크립팅 백엔드 — Mono로 냈다면 되돌리기 어렵습니다
Unity의 스크립팅 백엔드는 빌드 산출물의 구조 자체를 바꿉니다. Mono로 빌드하면 C# 코드가 관리형 어셈블리로 남아 디컴파일러로 열어볼 수 있습니다. IL2CPP는 네이티브 바이너리로 변환합니다.
바꾸는 것 자체는 설정 한 줄이지만, 출시 이후에 바꾸면 그때부터가 문제입니다. 빌드 시간과 산출물 크기가 달라지고, 네이티브 플러그인·리플렉션·직렬화 쪽에서 이전에 없던 문제가 나옵니다. 라이브 서비스 중에 이걸 검증할 여유가 있는 팀은 많지 않습니다.
IL2CPP가 만능이라는 뜻은 아닙니다. 메타데이터가 남기 때문에 복원 도구로 상당 부분 되살릴 수 있습니다. 자세한 내용은 IL2CPP는 정말 안전한가에 정리했습니다. 여기서 하려는 말은 하나입니다. 어느 쪽을 쓸지는 출시 전에 정하고 그 상태로 검증까지 끝내는 편이 낫습니다.
2. 서명과 패키지 무결성 — 나중에 손대면 설치 기반이 흔들립니다
앱 서명은 보안 설정이라기보다 정체성에 가깝습니다. 서명이 바뀌면 스토어와 기기 입장에서는 다른 앱이 됩니다.
Android는 Play 앱 서명을 쓰면 키 교체 경로가 있긴 하지만 절차가 무겁고, 이미 설치된 사용자에게 영향이 갈 수 있습니다. 출시 전에 확인해 둘 것은 이 정도입니다.
- 서명 키를 어디에 보관하고, 누가 접근할 수 있는지 정해져 있는가
- 빌드 파이프라인이 매번 같은 키로 서명하는가
- 패키지가 변조되었는지 판단할 기준이 빌드에 들어가 있는가
세 번째가 특히 나중에 붙이기 번거롭습니다. 리패키징된 빌드를 판별하려면 정상 빌드가 어떤 상태여야 하는지를 알아야 하는데, 그 기준은 빌드 시점에 만들어집니다. 리패키징 공격의 흐름은 유니티 MOD APK 방지 가이드에서 다뤘습니다.
3. 서버가 최종 판정하는 값의 경계 — 가장 늦게 고치는 만큼 가장 비쌉니다
다섯 가지 중 나중에 바꾸기가 가장 어려운 항목입니다. 코드가 아니라 데이터 구조와 유저 기록이 얽히기 때문입니다.
출시 전에 답해 두면 좋은 질문은 이것입니다. "이 값이 조작되면 다른 유저나 매출에 영향이 가는가?"
그렇다면 그 값의 최종 판정은 서버에 있어야 합니다. 재화 잔액, 결제 지급 여부, 랭킹 점수 같은 것들입니다. 클라이언트가 계산해서 서버에 통보하는 구조로 출시해 버리면, 나중에 서버 판정으로 바꿀 때 이미 쌓인 기록을 어떻게 처리할지부터 정해야 합니다. 조작된 값과 정상 값을 사후에 구분하기 어려운 경우가 많습니다.
전부 서버로 옮기라는 뜻은 아닙니다. 싱글 콘텐츠의 연출 값까지 서버가 판정할 이유는 없습니다. 경계를 어디에 그을지를 출시 전에 정해 두라는 뜻입니다. 세이브 데이터 쪽 사례는 게임 세이브 파일 변조에 있습니다.
4. 빌드에 남는 것들 — 제출 전에 한 번은 열어보세요
개발 중에는 필요했지만 출시 빌드에 남으면 곤란한 것들이 있습니다. 대부분 알고 있으면서도 마감에 쫓겨 놓칩니다.
- 개발·스테이징 서버 주소가 빌드에 남아 있지 않다.
- 테스트 계정, 치트 명령, 디버그 메뉴 진입 경로가 제거되었다.
- 디버그 심볼과 상세 로그가 릴리스 설정에 맞게 정리되었다.
- 사용하지 않는 개발용 라이브러리가 패키지에 포함되어 있지 않다.
- 서버 API 키나 비밀값이 클라이언트에 들어 있지 않다.
마지막 항목만 성격이 다릅니다. 앞의 넷은 정리하면 끝나지만, 클라이언트에 넣은 비밀값은 이미 유출된 것으로 봐야 합니다. 빌드는 사용자 기기에 있고, 그 안의 문자열은 결국 읽힙니다. 발견했다면 제거가 아니라 교체가 필요합니다.
5. 탐지 이후에 무엇을 할지 — 정책이 없으면 라이브에서 결정하게 됩니다
탐지를 켜는 것과 탐지 결과로 무언가를 하는 것은 다른 일입니다. 그리고 후자는 출시 전에 정해 두지 않으면, 실제 사건이 터진 새벽에 정하게 됩니다.
정해 둘 것은 세 가지입니다.
- 무엇을 할 것인가 — 기록만 남길지, 경고할지, 차단할지. 항목마다 다를 수 있습니다.
- 오탐이 나오면 어떻게 할 것인가 — 정상 유저가 걸렸을 때 되돌리는 경로가 있는지.
- 누가 판단하는가 — 자동 처리 범위와 사람이 확인할 범위의 경계.
오탐 대응 경로가 없는 상태로 차단을 켜는 것이 실무에서 가장 위험합니다. 정상 유저 몇 명을 잘못 막으면 그 손해가 치터 몇 명을 놓친 것보다 큽니다. 처음에는 기록만 남기고, 데이터가 쌓인 뒤 강도를 올리는 순서가 안전합니다.
도입 방식 자체를 고민 중이라면 자체 개발과 상용 SDK 비교가 참고가 됩니다.
제출 전 최종 점검
앞의 다섯 가지를 한 번에 확인할 수 있게 정리했습니다.
빌드 설정
- 스크립팅 백엔드를 확정하고 그 설정으로 QA를 마쳤다.
- 서명 키의 보관 위치와 접근 권한이 정해져 있다.
- 패키지 변조를 판별할 기준이 빌드에 포함되어 있다.
구조
- 조작되면 다른 유저나 매출에 영향을 주는 값의 최종 판정이 서버에 있다.
- 클라이언트가 판정하는 값과 서버가 판정하는 값의 경계가 문서로 남아 있다.
빌드 잔여물
- 개발 서버 주소, 테스트 계정, 디버그 진입 경로가 제거되었다.
- 클라이언트에 비밀값이 들어 있지 않다. 있었다면 교체했다.
운영 준비
- 탐지 항목별로 무엇을 할지 정해져 있다.
- 오탐을 되돌리는 경로가 있다.
- 초기에는 기록 중심으로 시작하기로 합의되어 있다.
OZero Security를 검토 중이라면
이 글의 다섯 가지 중 저희가 돕는 것은 1·2번의 일부와 5번입니다. Check Setup이 IL2CPP가 아닌 프로젝트를 알려 주고 Android 서명 인증서와 manifest 서명을 확인하며, 탐지 뒤의 대응(로그·콜백·종료)은 Response Settings에서 정합니다. 3·4번은 게임 설계와 서버, 출시 절차의 몫이라 저희가 대신할 수 없습니다.
도입 부담에 관해서만 덧붙이면, 패키지를 임포트하면(Asset Store 구매분은 Package Manager의 My Assets, 고객 포털 다운로드분은 .unitypackage) Welcome 창이 열립니다. Check Setup이 프로젝트에 남은 설정을 보여 주고, Auto Setup이 권장 설정을 한 단계씩 확인받아 적용하며, 모듈은 Project Settings > OZero Security에서 설정합니다. 씬을 고치거나 게임 로직을 바꿀 필요는 없습니다. 출시 직전에 검토하시더라도 1번과 2번보다는 부담이 작습니다.
다만 순서는 지켜 주시는 편이 좋습니다. 스크립팅 백엔드와 서명 체계가 먼저 정해져야 그 위에서 무결성 검증이 의미를 갖습니다.
결론: 나중에 할 수 있는 것과 없는 것을 나누세요
출시 전 보안 점검을 "보안을 얼마나 갖췄나"로 접근하면 끝이 없습니다. 완벽한 상태로 출시하는 팀은 없습니다.
대신 이렇게 나눠 보세요. 나중에 붙일 수 있는 것과 지금 정해야 하는 것. 이 글의 다섯 가지가 후자입니다. 나머지는 출시하고 반응을 본 뒤에 붙여도 늦지 않습니다.
다음 단계
- 보호 범위 확인하기 — 플랫폼별 지원 사양과 플랜(Standard / Pro)별 방어 범위를 확인하세요.
- 빠른 통합 시작하기 — 패키지 임포트와 설정 절차는 통합 가이드에 있습니다.
- 기술 문의 및 상담 — 출시 일정이 촉박하다면 현재 구성으로 무엇이 가능한지 문의해 주세요.