2020년에 나온 위치 기반 크립토 아이디어 대부분이 조용히 사라진 이유는 GPS를 믿었기 때문입니다. GPS는 어떤 수신기든 들을 수 있는 방송 신호이고, 수신기에게 들은 내용을 거짓으로 말하라고 시킬 수도 있습니다. 그런 도구는 아마존에서 약 30달러면 살 수 있고, 2015년부터 줄곧 그랬습니다. 어떤 좌표에 서 있는 대가로 지갑에 돈을 주면서, 서 있었는지를 GPS만으로 검증하는 프로토콜은 소파에 누워 있는 가짜 지갑들에게 돈을 잃게 됩니다. 어려운 공격도, 교묘한 공격도 아닙니다.
위치 증명은 이 문제를 해결하는 계층입니다. 이 말은 정의되는 것보다 쓰이는 경우가 훨씬 많으니, 정의부터 시작하겠습니다. 위치 증명이란 특정 기기가 특정 시간대에 특정 좌표에 있었다는 주장으로, 그 자리에 없었던 제3자가 검증할 수 있는 것을 말합니다. 좌표에 대한 주장이 아니라 실제로 그곳에 있었다는 것에 대한 주장입니다. 엔지니어링의 대부분은 바로 이 차이에 있습니다.
위협 모델. 저희가 막으려는 상대는 국가 단위의 공격자가 아닙니다. 그런 극단적인 경우는 마지막에 다루겠습니다. 저희가 막으려는 것은 휴대폰 한 대, 노트북 한 대, 그리고 오후 한나절을 가진 평범한 공격자입니다. 이런 공격자는 시중의 도구로 GPS를 속이고, 에뮬레이터에서 앱을 실행하고, 코드 한 줄로 지갑을 만들어 낼 수 있습니다. 어떤 단일 통제 수단이든 이 공격자에게 뚫릴 수 있습니다. 엔지니어링의 목표는 그 모든 수단을 한꺼번에 뚫는 비용을 드롭에 걸린 보상보다 크게 만드는 것입니다.
이 글은 Seek이 지금 하고 있는 일과 앞으로 할 일을 쉬운 말로 설명합니다. 일부러 마케팅 이야기는 줄이고 작동 방식은 길게 다뤘습니다.
1계층, 포획 시점: 기기 인증. 모든 포획 요청에는 운영체제가 서명한 진술이 함께 전달됩니다. iOS에서는 Apple App Attest, Android에서는 Google Play Integrity입니다. Seek은 서버에서 두 가지 모두를 검증합니다. 인증은 하나의 서명으로 세 가지를 말해 줍니다. 이것이 실제 기기라는 것, 앱 바이너리가 변조되지 않았다는 것, 그리고 호출자가 이 기기에서 저희 앱 번들을 위해 생성된 키를 가지고 있다는 것입니다. 루팅된 휴대폰은 통과하지 못합니다. 에뮬레이터도 통과하지 못합니다. 위치 확인을 건너뛰도록 다시 패키징된 앱도 통과하지 못합니다. 인증은 휴대폰이 어디에 있는지를 증명하지 않습니다. 휴대폰이 자신이 휴대폰이라는 사실에 대해 거짓말을 하지 않는다는 것을 증명합니다. 그래서 다른 신호들을 읽을 가치가 생깁니다.
2계층, 포획 시점: 여유 범위가 있는 거리 확인. 클라이언트는 여러분이 스폰의 수집 반경 안에 있을 때만 포획 버튼을 누를 수 있게 합니다. 서버는 여러분이 보낸 좌표를 스폰 좌표와 따로 비교하며, 최대 75미터까지의 차이를 허용합니다. 버튼 반경과 서버 반경 사이의 차이는 의도한 것입니다. 벽에 기댄 휴대폰의 GPS는 여러분 잘못이 아닌 이유로 몇 미터씩 흔들릴 수 있고, 그 흔들림 범위 안에서 포획을 거부하면 제멋대로라는 느낌을 줍니다. 75미터를 넘으면 요청은 바로 거부되며, 이 계층에서는 점수 산정도 이의 제기도 없습니다.
2계층 이어서: 요청 빈도 제한과 스폰별 상한. 5초 이내에 두 번 수집 요청을 보내면, 서버리스 인스턴스 간에도 유지되는 Postgres 기반 게이트가 429를 돌려줍니다. 하나의 스폰은 같은 계정에서 최대 두 번까지만 시도를 받으며, 두 번째 시도의 가치는 첫 번째의 65퍼센트입니다. 이 상한은 부정 행위 탐지를 위한 것이 아닙니다. 이미 다른 계층을 뚫은 봇이라도 사람이 플레이하는 속도보다 빠르게 이 엔드포인트를 채굴하지 못하게 하려는 것입니다.
3계층, 포획 시점: 환경 신호. 기록하되 강제하지는 않습니다. 모든 포획에는 몇 가지 플래그가 함께 전달됩니다. 요청이 시뮬레이터에서 왔는지, Android가 위치를 모의 위치 제공자에서 받았다고 보고했는지, 그리고 보고된 GPS 정확도(미터 단위)입니다. 이 값들은 기록되지만, 포획 자체를 거부하는 데는 절대 쓰이지 않습니다. 이 값들에 대해 거짓말을 하는 클라이언트야말로 결정을 맡겨서는 안 되는 클라이언트이므로, 결정은 다른 곳에서 내려집니다. 이 신호들은 4계층에서 의미를 갖습니다.
4계층, 출금 시점: 부정 행위 게이트. 출금은 해당 계정의 최근 90일간 포획 기록을 읽는 서버 함수를 거칩니다. 그중 하나라도 시뮬레이터에서 왔거나, Android가 모의 위치 제공자를 보고했거나, 계정이 10초 이내에 두 번 포획에 성공했거나, 두 포획 좌표 사이를 사람이 이동할 수 있는 속도보다 빠르게 이동했거나, 다른 계정이 같은 기기 지문으로 출금한 적이 있다면, 그 출금은 자동 승인되지 않고 사람의 검토로 넘어갑니다. 사용자에게는 어떤 경보가 울렸는지 알려 주지 않으며, 계정은 평소처럼 계속 플레이할 수 있습니다. 탐지는 지급에 관한 비즈니스 판단이지, 처벌이 아닙니다.
포획과 출금을 나누는 이유는 두 단계가 서로 다른 것을 지키기 때문입니다. 포획 계층은 게임을 지킵니다. 부정한 포획이라도 그것은 앱 밖으로 나가지 못하는 게임 재화가 될 뿐이라 비용이 들지 않습니다. 출금 계층은 실제 돈을 지킵니다. 시스템을 빠져나가는 모든 돈은 그 잔액이 어떻게 쌓였는지에 대한 90일간의 검토를 거치며, 그 기간에 의심스러운 신호가 하나라도 있으면 결정은 사람에게 넘어갑니다. 두 계층이 함께 작동하기 때문에, 정상적인 플레이어는 포획하는 순간에 어떤 불편도 겪지 않고, 부정한 포획을 슬쩍 통과시킨 공격자는 결코 돈을 손에 쥐지 못합니다.
5계층, 포획 시점: 움직임 기록. 모든 휴대폰에는 GPS와 같은 칩에서 통신하는 가속도계와 자이로스코프가 있습니다. Seek은 이제 포획 직전 몇 초 동안의 움직임을 짧게 기록하고, 몇 가지 통계(크기의 분산, 회전 활동, 정지 프레임 수)를 계산해, 그 요약을 수집 요청과 함께 보냅니다. 스폰까지 걸어간 휴대폰은 GPS 시뮬레이터를 켜 둔 채 책상 위에 놓인 휴대폰과 움직임의 특징이 다릅니다. 이 특징은 지금은 포획 계층에서 강제되지 않습니다. 환경 플래그와 같은 이유, 즉 변조된 클라이언트가 거짓말을 할 수 있기 때문입니다. 대신 시뮬레이터 및 모의 위치 제공자 신호와 함께 90일 부정 행위 게이트로 들어가며, 기록에 남은 평평한 움직임 기록은 출금을 사람의 검토로 넘기는 또 하나의 경보가 됩니다.
실제 예를 들어 보겠습니다. 한 테스터가 GPS 스푸퍼를 실행해 좌표를 도시 반대편의 Seek 드롭에 맞추고 포획을 누릅니다. 스푸핑된 좌표가 일치하므로 거리 확인은 통과합니다. 앱이 변조되지 않았으므로 인증도 통과합니다. 포획이 등록됩니다. 두 시간 뒤 같은 테스터가 세 번 더 포획하는데, 그중 하나는 10킬로미터 떨어진 다른 좌표입니다. 네 번 모두 움직임 기록은 평평하고(휴대폰은 한 번도 움직이지 않았습니다), 두 시간 안에 걸어서 갈 수 없는 두 좌표에 대해 불가능한 이동 검사가 작동합니다. 계정은 평소처럼 플레이하고 수집하며, 뭔가 잘못되었다는 사실을 전혀 모릅니다. 테스터가 출금을 요청하면, 그 요청은 불가능한 이동 플래그와 평평한 움직임 기록이 첨부된 채 사람의 검토 창구로 넘어갑니다. 검토자는 이를 거부합니다. 테스터가 모은 40달러의 잔액은 앱 밖에서는 결코 아무런 가치를 갖지 못합니다.
경제적인 관점. 중요한 것은 포획 자체를 속이는 것이 불가능하다는 점이 아니라, 출금 게이트가 그 잔액에 이르기까지 계정이 한 모든 일을 되짚어 읽는다는 점입니다. 인증과 거리 확인으로 보호되는 2유로짜리 드롭은 한 번 공격하기에는 싸지만 반복해서 공격할 의미가 없습니다. 그 패턴이 돈이 되기 전에 출금 검사가 패턴을 잡아내기 때문입니다. 1만 유로짜리 드롭이라면 포획 계층에서 더 강한 틀이 필요하며, 아래 로드맵이 바로 그 이야기입니다.
로드맵에 있는 것. 다음으로 도입될 통제 수단은 실내 드롭을 위한 비콘 대체 수단입니다. GPS가 의미 없는 건물 안에 놓인 스폰의 경우, 해당 드롭에 등록된 작은 블루투스 비콘이 있으면 앱은 위성 신호에 전혀 의존하지 않고도 방문을 증명할 수 있습니다. 두 번째 과제는 인증의 강제 적용입니다. 지금은 인증되지 않은 요청도 기록만 하고 받아들이고 있는데, 스위치를 켜서 이를 바로 거부하기 전에 정상 기기에 대한 오거부율을 먼저 측정하기 위해서입니다. 두 가지 모두 이미 쓰고 있는 포획 및 출금 구조에 작고, 평범하고, 검증 가능한 추가 기능으로 들어갑니다.
아직 잘 안 되는 것. 쇼핑몰 안에서 실내 GPS는 10~15미터씩 어긋나고, 서버를 아무리 영리하게 만들어도 이는 고쳐지지 않습니다. 진짜 해답은 비콘이며, 그래서 로드맵에 올라 있습니다. 1초 미만의 지연 시간은 지금 불가능하고 앞으로도 아마 그럴 것입니다. 부정 행위 게이트는 단일 요청이 아니라 기록 전체를 읽기 때문입니다. 웨어러블은 휴대폰보다 센서 구성이 단출해서, 휴대폰에 맞춰 조정된 위치 증명 설계가 안경으로 깔끔하게 옮겨 가지 않습니다. 그리고 트럭 한 대 분량의 RF 장비를 가진 국가 단위 공격자는 오늘날 어떤 휴대폰 검증기든 무력화할 수 있습니다. 그렇지 않다고 주장하는 프로토콜은 여러분에게 솔직하지 않은 것입니다. 저희는 그런 주장을 하지 않겠습니다.
소리 내어 말할 가치가 있는 설계 원칙이 있습니다. 검증기는 자신이 무엇을 증명할 수 있고 무엇을 증명할 수 없는지에 대해 솔직해야 합니다. 확률적인 점수를 절대적인 예/아니오처럼 내놓는 것은 엄격한 규칙에 따른 절대적인 예/아니오보다 나쁩니다. 점수는 슬라이더를 만들고, 참여 목표에 미달할 때면 어떤 슬라이더든 더 많은 주장을 받아들이는 쪽으로 밀리기 때문입니다. 저희 포획 계층에는 슬라이더가 없습니다. 검사를 통과하거나, 통과하지 못하거나 둘 중 하나입니다. 부정 행위 계층에는 슬라이더가 있지만, 그 슬라이더는 코드가 아니라 사람의 손에 있습니다.
앵커드 자산과 위치 검증 에어드롭을 할 가치가 있게 만드는 것이 바로 Seek 밑에 있는 이 부분입니다. 발행자가 실제 가치가 있는 토큰을 어떤 좌표에 두는 것은, 그것을 결국 가져가는 사람이 인증된 기기로 그 좌표에 있었고, 돈이 움직이기 전에 출금 게이트가 계정의 기록을 되짚어 읽기 때문입니다. 전체 명세는 백서에 있습니다. 이 글은 앱 안에서 일어나는 일을 쉬운 말로 옮긴 버전입니다.
짧게 정리하면 이렇습니다. 방문은 좌표가 아닙니다. 하나의 신호로는 방문을 증명할 수 없습니다. Seek은 두 단계로 방문을 검증합니다. 포획하는 순간의 인증, 거리, 움직임 기록, 그리고 출금하는 순간의 90일 부정 행위 게이트입니다. 아직 남은 하나인 실내 드롭용 비콘 대체 수단은 GPS만으로는 해결할 수 없는 마지막 좌표 문제를 메워 줄 것입니다. 이것이 오늘날 Seek 안에서 위치 증명이 실제로 의미하는 바이며, 이 계층이 그 위에서 가능해지는 어떤 화려한 기능보다도 중요한 이유입니다.


