Большинство крипто-идей 2020 года, основанных на местоположении, тихо умерли потому, что доверяли GPS. GPS это широковещательный сигнал, который может слушать любой приёмник, а приёмник можно заставить лгать о том, что он услышал. Инструменты для этого стоят около тридцати долларов на Amazon, и так с 2015 года. Любой протокол, который платит кошельку за то, что тот стоит на координате, и проверяет это только по GPS, теряет деньги на поддельных кошельках, лежащих на диване. Это не сложная атака и не хитрая.
Доказательство местоположения это слой, который это исправляет. Выражение используют чаще, чем определяют, поэтому начнём с определения. Доказательство местоположения это утверждение, которое может проверить сторона, не присутствовавшая при событии, что конкретное устройство было на конкретной координате в конкретное окно времени. Это утверждение о присутствии, а не о координате. Именно в этом различии кроется большая часть инженерной работы.
Модель угроз. Мы не защищаемся от государства; этот предельный случай будет в конце. Мы защищаемся от среднего атакующего с телефоном, ноутбуком и свободным днём. Такой атакующий может подделать GPS готовым инструментом, запустить приложение в эмуляторе и создать кошелёк одной строкой кода. Любую отдельную защиту такой атакующий может обойти. Инженерная цель в том, чтобы обход всех защит вместе стоил дороже награды за дроп.
Эта статья простыми словами описывает, что Seek делает сегодня и что на подходе. Маркетинговой части в ней сознательно меньше, а механики больше.
Слой первый, в момент поимки: аттестация устройства. Каждый запрос на поимку несёт подписанное заявление операционной системы. На iOS это Apple App Attest, на Android это Google Play Integrity. Seek проверяет оба на сервере. Аттестация одной подписью говорит три вещи: это настоящее устройство, бинарник приложения не изменён, и у отправителя есть ключ, созданный на этом устройстве для нашего пакета. Телефон с root-доступом не проходит. Эмулятор не проходит. Пересобранное приложение, пропустившее проверку местоположения, не проходит. Аттестация не доказывает, где телефон; она доказывает, что телефон не лжёт о том, что он телефон. Именно поэтому остальные сигналы вообще стоит читать.
Слой второй, в момент поимки: расстояние с запасом. Клиент позволяет нажать кнопку поимки, только когда ты находишься в радиусе сбора спавна. Сервер независимо сверяет присланные координаты с координатами спавна и допускает расхождение до семидесяти пяти метров. Разница между радиусом кнопки и радиусом сервера намеренная. Дрожание GPS у телефона, прислонённого к стене, может уводить позицию на несколько метров не по твоей вине, и отказ в поимке внутри этого дрожания выглядел бы произвольным. Дальше семидесяти пяти метров запрос сразу отклоняется, без оценки и без апелляции на этом слое.
Слой второй, продолжение: ограничения частоты и лимиты на спавн. Два запроса на сбор с интервалом меньше пяти секунд получают ответ 429 от ограничителя на базе Postgres, который работает во всех бессерверных изолятах. Один спавн принимает не больше двух попыток от одного аккаунта, и вторая попытка стоит 65 процентов от первой. Эти лимиты существуют не для выявления мошенничества; они нужны, чтобы бот, уже обошедший остальные слои, не мог добывать из эндпоинта быстрее, чем играет человек.
Слой третий, в момент поимки: сигналы окружения, которые записываются, но не применяются. Каждая поимка также несёт флаги: пришёл ли запрос из симулятора, сообщил ли Android, что позиция получена от фиктивного источника местоположения, и заявленная точность GPS в метрах. Они записываются и никогда не используются для отказа в самой поимке. Клиент, который о них лжёт, это именно тот клиент, которому нельзя доверять решение, поэтому решение принимается в другом месте. Они важны на четвёртом слое.
Слой четвёртый, в момент выплаты: антифрод-фильтр. Выводы проходят через серверную функцию, которая читает поимки аккаунта за последние девяносто дней. Если какая-то из них пришла из симулятора, или Android сообщил о фиктивном источнике, или аккаунт сделал две успешные поимки с интервалом меньше десяти секунд, или аккаунт перемещался между двумя координатами поимок быстрее, чем может человек, или с того же отпечатка устройства выводил средства другой аккаунт, вывод направляется на проверку человеку, а не одобряется автоматически. Пользователю не сообщают, что именно сработало, и его аккаунт продолжает играть как обычно. Выявление это деловое решение о выплатах, а не наказание.
Поимку и выплату разделяют потому, что они защищают разное. Слой поимки защищает игру. Если поимка была мошеннической, она превращается в игровую валюту, которая никогда не покидает приложение, и это ничего не стоит. Слой выплаты защищает реальные деньги. Каждый доллар, покидающий систему, проходит девяностодневную проверку того, как сложился баланс, и одного подозрительного сигнала в этом окне достаточно, чтобы передать решение человеку. Вместе эти два слоя означают, что честный игрок никогда не встречает препятствий в момент поимки, а атакующий, протащивший плохую поимку, никогда не видит денег.
Слой пятый, в момент поимки: данные движения. В каждом телефоне есть акселерометр и гироскоп на том же чипе, что работает с GPS. Теперь Seek записывает короткое окно движения за секунды до поимки, вычисляет небольшой набор статистик (дисперсия величины, вращательная активность, число неподвижных кадров) и отправляет эту сводку вместе с запросом на сбор. У телефона, который дошёл до спавна, профиль движения отличается от телефона, лежащего на столе с запущенным GPS-симулятором. Сегодня этот профиль не применяется на слое поимки по той же причине, что и флаги окружения: изменённый клиент может лгать. Он попадает в девяностодневный антифрод-фильтр вместе с сигналами симулятора и фиктивного источника, и плоские данные движения в истории становятся ещё одним сигналом, который передаёт вывод на проверку человеку.
Разберём пример. Тестировщик запускает подделку GPS, ставит координату дропа Seek на другом конце города и нажимает «поймать». Проверка расстояния проходит, потому что поддельная координата совпадает. Аттестация проходит, потому что приложение не изменено. Поимка засчитывается. Через два часа тот же тестировщик делает ещё три поимки, одну из них с другой координаты в десяти километрах. Данные движения во всех четырёх плоские (телефон не двигался), а проверка невозможного перемещения срабатывает на двух координатах, до которых нельзя было дойти пешком за два часа. Аккаунт продолжает играть, продолжает собирать и не подозревает, что что-то не так. Когда тестировщик запрашивает выплату, она попадает на стол проверяющего с приложенными флагом невозможного перемещения и плоскими данными движения. Проверяющий отказывает. Собранные тестировщиком сорок долларов баланса так ничего и не стоят за пределами приложения.
Экономическая рамка. Важно не то, что подделать саму поимку невозможно; важно, что фильтр выплат просматривает всё, что аккаунт сделал, чтобы получить баланс. Дроп стоимостью два евро, защищённый аттестацией и проверкой расстояния, дёшево атаковать один раз и бессмысленно атаковать повторно, потому что проверка вывода ловит закономерность раньше, чем закономерность превращается в деньги. Дропу стоимостью десять тысяч евро нужна более сильная рамка на слое поимки, и об этом дорожная карта ниже.
Что в дорожной карте. Следующей появится запасная проверка по маячку для дропов в помещениях. Для спавна внутри здания, где GPS бесполезен, небольшой Bluetooth-маячок, зарегистрированный за дропом, позволяет приложению доказать присутствие, вообще не завися от спутниковой позиции. Второе направление это принудительная аттестация: сегодня запросы без аттестации записываются, но всё ещё принимаются, чтобы мы могли измерить долю ложных отказов для честных устройств, прежде чем включить переключатель и отклонять их сразу. И то и другое появится как небольшие, скучные, проверяемые дополнения к уже работающей схеме поимки и выплаты.
Что пока работает плохо. GPS в помещении ошибается на десять-пятнадцать метров в торговом центре, и никакая хитрость на сервере этого не исправит; настоящий ответ это маячок, поэтому он и в дорожной карте. Задержки меньше секунды нет и, вероятно, не будет, потому что антифрод-фильтр читает историю, а не один запрос. У носимых устройств меньше датчиков, чем у телефонов, поэтому схема доказательства местоположения, настроенная под телефоны, не переносится на очки один в один. И государство с грузовиком радиооборудования сегодня может обойти любой мобильный верификатор; любой протокол, который утверждает обратное, с тобой нечестен. Наш не будет.
Принцип проектирования, который стоит произнести вслух. Верификатор должен честно говорить, что он может доказать, а что нет. Выдавать вероятностную оценку за абсолютное «да» или «нет» хуже, чем давать абсолютное «да» или «нет» по строгим правилам, потому что оценка создаёт ползунок, а любой ползунок сдвигают в сторону принятия большего числа заявок, когда отстают цели по вовлечённости. На нашем слое поимки ползунка нет. Проверки либо пройдены, либо нет. На антифрод-слое ползунок есть, и он находится у человека, а не в коде.
Это та часть Seek, благодаря которой активы с якорем и аирдропы с проверкой местоположения имеют смысл. Паблишер размещает токен, стоящий реальных денег, на координате, потому что тот, кому он достанется, был на этой координате с аттестованным устройством, и потому что фильтр выплат просмотрит историю аккаунта, прежде чем деньги сдвинутся с места. Полная спецификация есть в whitepaper. Эта статья простая версия того, что происходит внутри приложения.
Коротко. Присутствие это не координата. Один сигнал не доказывает присутствие. Seek проверяет присутствие в два слоя: аттестация, расстояние и данные движения в момент поимки и девяностодневный антифрод-фильтр в момент выплаты. Остающийся открытым пункт, запасная проверка по маячку для дропов в помещениях, закрывает последний случай с координатами, с которым GPS в одиночку не справляется. Вот что на самом деле представляет собой доказательство местоположения в Seek сегодня, и поэтому этот слой важнее всех более эффектных вещей, которые он делает возможными.


