Привет! Меня зовут Тоня, я продуктовый разработчик в продукте QIWI Кошелек. Недавно мы делали задачу по предотвращению рисков в связи с использованием приложения с Jailbreak. Хочу рассказать о трудностях, с которыми столкнулись на пути, и о том, как мы их разрешили.

Кто такой этот ваш Jailbreak?

Наверное, каждый хоть раз слышал слово jailbreak, но давайте разберемся, зачем это нужно, чем опасно и как его обнаружить. 

Дословно jailbreak переводится как «побег из тюрьмы» или «взлом». Данный термин, как правило, используется в отношении iOS. Простыми словами — это использование уязвимостей устройства для получения полного доступа к операционной системе. Из-за такого полного доступа к системе появляется и доступ до keychain, который становится уже не таким защищенным. После взлома у пользователя появляется доступ к альтернативным сторам, из которых можно скачать приложения, не проходившие ревью в App Store. Одним из самых популярных таких альтернативных сторов является Cydia, который чаще всего сразу же устанавливается в момент взлома устройства. 

Зачем его отслеживать?

После джейлбрейка у мошенников появляется возможность взлома устройства по нескольким причинам. Приложения, которые становится возможным скачать в результате джейлбрейка, не проверяются никем, в отличие от случая с App Store, поэтому могут  быть небезопасны. Также Apple не поддерживает устройства с jailbreak, из-за чего после взлома они перестают получать важные обновления, в том числе обновления системы безопасности. В случае взлома устройства компания Apple аннулирует гарантию на него, и при поломке его уже нельзя будет отремонтировать в официальном сервисе. 

Чем же это может быть опасно для вашего приложения? Если оно работает с персональными данными либо с денежными средствами — следует, как минимум, предупредить пользователя о том, что это небезопасно. Тем более, это будет небезопасно, если ваше приложение используется в качестве двухфакторной аутентификации. Так как устройство не получает необходимые обновления безопасности, это упрощает для мошенников получение доступа к данным, например с использованием приложений, которые не проходили ревью от Apple. 

Мы реализовывали проверку устройства на JailBreak, прежде чем предоставить пользователю возможность подключить себе Apple Pay, для того, чтобы избежать быстрого и простого доступа мошенников к картам. Но с уходом Apple Pay эта проблема стала уже не такой актуальной.

В памятке Центрального банка о мерах по обеспечению безопасности при работе в системе дистанционного банковского обслуживания физических лиц Банка России сказано следующее:

В целях минимизации рисков при использовании Системы дистанционного банковского обслуживания Банк просит клиентов для обеспечения безопасности их денежных средств не выполнять операции по повышению привилегий или взлому операционной системы мобильного устройства (получение root-прав для Android, установка jailbreak для iOS), на котором установлено или планируется установка мобильного приложения. Не устанавливать мобильное приложение на устройство, которое уже получило такие привилегии.

Данный пункт памятки приводит нас к тому, что в банковских приложениях необходимо отслеживать jailbreak и предупреждать пользователя о всех рисках, связанных со взломом.

Как же его отследить?

Есть несколько признаков того, что на телефоне настроен jailbreak. Вот так реализовали проверку мы:

  1. Наличие альтернативных сторов на устройстве. В первую — очередь проверка стора Cydia. Сделать это можно несколькими способами. Например, проверить, устройство на наличие обработчика протокола cydia://: вот так:

static func hasCydiaInstalled() -> Bool {

        return UIApplication.shared.canOpenURL(URL(string: "cydia://")!)

    }

Либо можно просто проверить, установлены ли сторонние сторы на устройстве. Вот список таких сторов:

private static var suspiciousAppsPathToCheck: [String] {

        return [

            "/Applications/Cydia.app",

            "/Applications/blackra1n.app",

            "/Applications/FakeCarrier.app",

            "/Applications/Icy.app",

            "/Applications/IntelliScreen.app",

            "/Applications/MxTube.app",

            "/Applications/RockApp.app",

            "/Applications/SBSettings.app",

            "/Applications/WinterBoard.app",

        ]

    }

Для того чтобы узнать, есть ли эти приложения на устройстве, нужно проверить с помощью FileManager, существует ли какой-нибудь файл на устройстве из списка, написанного ранее.

for path in suspiciousAppsPathToCheck where FileManager.default.fileExists(atPath: path) {

            return true

        }

  1. Проверить устройство на наличие подозрительных файлов. К списку таких файлов можно отнести следующие:

static var suspiciousSystemPathsToCheck: [String] {
return [
     "/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",       
     "/Library/MobileSubstrate/DynamicLibraries/Veency.plist",
     "/private/var/lib/apt",
     "/private/var/lib/apt/",
     "/private/var/lib/cydia",
     "/private/var/mobile/Library/SBSettings/Themes",
     "/private/var/stash",
     "/private/var/tmp/cydia.log",
     "/System/Library/LaunchDaemons/com.ikey.bbot.plist",
     "/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
     "/usr/bin/sshd",
     "/usr/libexec/sftp-server",
     "/usr/sbin/sshd",
     "/etc/apt",
     "/bin/bash",
     "/Library/MobileSubstrate/MobileSubstrate.dylib"
 ]
}

Проверка на наличие этих файлов осуществляется так же, как и проверка на наличие подозрительных сторов — с помощью FileManager:

static func isSuspiciousSystemPathsExists() -> Bool {
        for path in suspiciousSystemPathsToCheck {
            if FileManager.default.fileExists(atPath: path) {
                return true
            }
        }
        return false
    }

Список таких файлов и приложений может постепенно пополняться. Наиболее актуальные списки можно найти на разных ресурсах в открытом доступе, например вот тут.

  1. Проверить, может ли приложение создавать или изменять файлы, которые находятся за пределами изолированной среды приложения. Например, может ли приложение записать текст в файл в каталоге /private. Если ошибок во время выполнения этого действия не возникнет — устройство взломано:

static func canEditSystemFiles() -> Bool {
    let jailBreakText = "Device is JailBroken ????"
    do {
        try jailBreakText.write(toFile: "/private/jailbreak.txt", atomically: true, encoding: .utf8)
        return true
    } catch {
        return false
    }
}
  1. Также проверить доступ к подозрительным файлам можно проверить с помощью функции fopen():

if UnsafeMutablePointer<FILE>(fopen("/bin/bash", "r")) != nil ||

            UnsafeMutablePointer<FILE>(fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r")) != nil ||

            UnsafeMutablePointer<FILE>(fopen("/usr/sbin/sshd", "r")) != nil ||

            UnsafeMutablePointer<FILE>(fopen("/etc/apt", "r")) != nil ||

            UnsafeMutablePointer<FILE>(fopen("/Applications/Cydia.app", "r")) != nil {

            return true

        }

По итогам всех проверок можно сказать — если хоть в одном из мест вернулось true, то мы можем утверждать, что на этом девайсе JailBreak.

Как предупредить пользователя и обезопасить приложение?

Лучше всего отловить пользователя с JailBreak до того, как он получит доступ к персональным данным или к денежным средствам. В нашей ситуации достаточно было лишь предупредить пользователя об опасности и сохранить данные о том, что он принял риски. 

Для этого мы проверяем устройство пользователя еще до того, как он успел войти в свой аккаунт. После чего в случае согласия на риски мы локально на устройстве сохраняем время и факт согласия. 

Также локальное хранилище помогает без авторизации отследить, предупреждали ли мы уже этого пользователя о рисках, или нет, чтобы каждый раз не показывать ему предупреждение при входе.

А как теперь все протестить?

Если вы уже попробовали эти проверки, наверняка заметили, что на симуляторе каждый раз показывается, что настроен JailBreak. Это происходит из-за того, что срабатывает проверка на открытие "/bin/bash".

Это упрощает тестирование и отладку работы проверки на JailBreak, но при этом создает проблемы для автотестов и для дальнейшей работы с симулятором. Исправить это можно простой проверкой на таргет устройства, на котором запущено приложение, до того, как начать проверять на наличие JailBreak на устройстве:

#if targetEnvironment(simulator)

        return false

#else

// все остальные проверки

#endif

А для того, чтобы написать автотесты на данную фичу, мы просто добавили новый булевый аргумент запуска приложения, который кидаем из автотестов и проверяем его перед началом всех проверок на JailBreak.

P.S.

Когда только реализовывали фичу, нам казалось, что в 2023 году уже никто не взламывает свои телефоны, но к нашему удивлению аналитика показала, что таких случаев достаточно. Поэтому данная задача потерять свою актуальность еще не успела. 

Полезные ссылки

Комментарии (28)


  1. SalazarMAX
    21.09.2023 12:43
    +12

    Почему я не могу пользоваться всеми функциями приложения на джейлбрейкнутом/рутованном смартфоне, но могу делать всё то же самое в браузере, только менее удобно? Не говоря уже о ПК, где рут-доступ есть по умолчанию.


    1. tonya_fedorova Автор
      21.09.2023 12:43
      +1

      Мы не запрещаем доступ к функциям приложения, а лишь предупреждаем пользователя об опасности использования такого устройства. А по поводу браузера - в случае попытки совершить платеж на сайте, необходимо подтвердить действие еще одним фактором безопасности - ввести код из смс/пуш, чего в мобильном приложении не требуется.


      1. SmileyK
        21.09.2023 12:43
        +1

        Почему это, при оплате в банковском приложении запрашивается второй фактор, лицом подтвердить/пальцем/ при использовании быстрых платежей в том жей райфе все равно ожидается пуш-код для подтверждения.... тут вопрос к Вам, как вы реализуете логику...


  1. VVitaly
    21.09.2023 12:43
    +2

    Читая подобные статьи я всегда удивляюсь...
    Неужели поколение современных прикладных разработчиков не знает такой простой и давно известной истины, что пользователь с root правами (а jailbreak на IOS как и root на Android именно эти права и позволяют получить) может "скрыть" от любого другого пользователя или программы работающих не от root (а все пользовательские приложения на IOS и Android таких прав не имеют) наличие у себя таких прав или любого приложения/файла на устройстве. Для этого достаточно просто иметь или соответствующие знания OS (в частности unix) или соответствующий сторонний софт (которого так же достаточно, если собственных знаний у вас нет).
    Ну ладно законодатели (они "слышали звон, но не знают где он"), но IT то специалисты... Куда же катится уровень знаний современных разработчиков.... :-)


    1. usrsse2
      21.09.2023 12:43
      +1

      Снаряд и броня – разработчики банковских приложений и Skype совершенствуют методы обнаружения джейлбрейка, разработчики твиков добавляют новые обходы для этих проверок.


      1. VVitaly
        21.09.2023 12:43
        +1

        :-) Да уж... Я еще понимаю когда разработчики OS под устройство "защищают" от получения root доступа... Но куда "впрягаются" и "надувают щеки" прикладники то? А главное это абсолютно безуспешно... Но видимо знание базовых принципов прав и разделения доступа в unix - им просто никто нормально не объяснил... :-)


    1. vadimr
      21.09.2023 12:43
      +2

      Проверка выполняется не для таких людей, которые в состоянии скрыть наличие у себя прав. А для обычных пользователей, которые настолько доверчивы, что предоставляют рутовые права неограниченному кругу лиц.


      1. VVitaly
        21.09.2023 12:43
        +1

        :-) Это да... Проще посадить ребенка под замок, чем его воспитывать...


  1. usrsse2
    21.09.2023 12:43
    +7

    if UnsafeMutablePointer<FILE>(fopen("/bin/bash", "r")) != nil ||
                UnsafeMutablePointer<FILE>(fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r")) != nil ||
                UnsafeMutablePointer<FILE>(fopen("/usr/sbin/sshd", "r")) != nil ||
                UnsafeMutablePointer<FILE>(fopen("/etc/apt", "r")) != nil ||
                UnsafeMutablePointer<FILE>(fopen("/Applications/Cydia.app", "r")) != nil {
                return true
            }
    

    А закрыть файл, если его удалось открыть?


    1. tonya_fedorova Автор
      21.09.2023 12:43
      +1

      Спасибо за хорошее замечание!
      В статье приведены абстрактные примеры кода, а реализации могут отличаться у всех.


      1. usrsse2
        21.09.2023 12:43
        +3

        Просто копипастить же начнут, это же код на Swift, а не псевдокод)


    1. VVitaly
      21.09.2023 12:43
      +1

      :-) Как то так примерно...
      #chown root.root /bin/bash
      #chmod 700 /bin/bash
      .......
      Для .app дать права +rx только пользователю с "нужным" id... У остальных отобрать.


  1. koreychenko
    21.09.2023 12:43
    +12

    А можно пару примеров реальных векторов атак? А то пока видится что-то из серии "Раз пользователь убежал из клетки, то он бандит и ужас-ужас мы на взломанном устройстве!"

    Было бы интереснее увидеть другую статью: "Наше приложение умеет безопасно работать в любой клоаке где его запускают. А ваши разработчики так умеют?".


  1. AlexeyK77
    21.09.2023 12:43
    +1

    По хорошему, если приложение работает на "взломанном" устройстве и политика компании позволяет работать на таком устройстве, то надо просто этому пользователю повышать риск фактор для антифродовых систем и вводить дополнительные проверки для операции.
    Удивительно, что таких джэйлбрейкнутых устройств по вашей статистике значительное количество, т.к. люди покупают яблочные устройства за удобство и безопасность экосистемы.


    1. vadimr
      21.09.2023 12:43

      Кто-то за удобство и безопасность, а кто-то потому что модно. Кроме того, существует ещё огромное количество устройств со вторичного рынка, зачастую устаревших, на которые штатным способом нужные приложения уже не поставить, так как они не поддерживаются современными версиями приложений, находящимися в App Store.


      1. Evengard
        21.09.2023 12:43

        Сейчас к обращающимся к джейлбрейку конкретно iOS добавились вероятно жители РФ, которые из-за санкций не могут поставить нужные приложения себе...


        1. vadimr
          21.09.2023 12:43
          +1

          Насколько я заметил, единственное, что не работает из-за санкций - это Apple Pay, который джейлбрейком не починить.


          1. Arty_Fact
            21.09.2023 12:43
            +1

            Как там приложения банков, обновляются?


            1. vadimr
              21.09.2023 12:43
              -1

              Да вроде никто не жалуется. Им-то чего сделается? Apple лениво банит старые релизы раз в полгода, банки лениво перевыпускают каждый релиз под новым id. Все при деле, ворон ворону глаз не выклюет, а для пользователей это прозрачно. Появляется в приложении кнопочка “Обновить”.

              По факту приложения банков для iOS и для Android синхронны.

              И как раз приложения банков не работают с джейлбрейком.


  1. exchange12rocks
    21.09.2023 12:43
    +3

    Что-то я не понял, это что, любое приложение на iOS может посмотреть какие ещё приложения установлены в системе? Получить доступ к практически произвольным файлам на устройстве???


    1. Finesse
      21.09.2023 12:43

      Закручивают гайки: https://habr.com/en/amp/publications/751128/


  1. daniilpashin
    21.09.2023 12:43
    +3

    Прошу прощения, но все приведенные проверки либо устарели, либо не будут работать должным образом.

    ...
    blackra1n.app
    FakeCarrier.app
    Icy.app
    ...

    Неужель у нас на дворе все еще 2013 год? Эти приложения пропали еще в те времена.

    jailBreakText.write(toFile: "/private/jailbreak.txt", atomically: true

    iOS приложения работают в песочнице как минимум. Вам система никогда не позволит записать файл вне песочницы, хоть 100500 джейлбрейков поставьте.

    fopen("/bin/bash"

    Чем fopen() в контексте проверки будет отличаться от stat(), указанного чуть выше по статье? Абсолютно ничем, разве что потратит лишние ресурсы. Про закрытие успешно открытого файла уже тут написали.

    По итогу: если хотите проверять на джейлбрейки, делайте это хотя бы правильно. Как Snapchat. Иначе получается какой-то детский сад из прошлого века

    P.S.: И тут еще в комментариях есть абсолютно верная мысль про абсолютную бесполезность таких детектов. Они почти все обходятся в два счета. Как минимум потому что вы и ваше приложение ограничено приватными API, а джейлбрейкеры - нет.


    1. VADemon
      21.09.2023 12:43

      верная мысль про абсолютную бесполезность таких детектов.

      Пока они не ограничивают пользователя в действиях - пускай. Предупреждение - это одно.

      Кстати задумался, каким боком в современной модели безопасности телефонов коды по SMS - безопасный канал? Нет, не говоря про атаки на сотовве сети, ЛЮБОЕ приложение с доступом к SMS (мы-то среднестатистического пользователя и про разрешения знаем) - потенциальная угроза. Не нужны никакие джейлбрейки и руты.


      1. vorphalack
        21.09.2023 12:43

        там еще другой прикол, создатели части банковских приложунек искренне считают что наличие интернета подразумевает наличие сотовой сети. подвалы с вайфаем передают привет...


        1. VADemon
          21.09.2023 12:43

          Не то что в подвале, у меня дома не ловится связь. В лучшем случае нестабильные 2 балки. Как оказалось (хвала приложениям), я ровно равноотдаленно от всех трех вышек, попросту в центре треугольника.

          Поддержка Voice-over-Wifi и т.п. оставляет желать лучшего из-за секретничанья операторов, их отсталости (это типа как "нахой нам IPv6") и необновления прошивок телефонов. Да, в каждом телефоне должны быть захардкожены параметры оператора во внутренностях прошивки - иначе адиос. Плюс к этому идет натуральный region lock - ну не будет же производитель пихать в европейскую прошивку настройки азиатских операторов. Как-то так.


          1. vorphalack
            21.09.2023 12:43

            VoWiFi это вообще далекая галактика, они VoLTE-то доделать не могут...


    1. AlexeyK77
      21.09.2023 12:43

      В нормах регулятора могут быть требования по поводу детекта рутизации устройства, поэтому хочешь не хочешь а делать формально проверку надо. По законам статистики все равно даже простые методы дадут детект в определенном проценте случаев, т.к. четких требваний по алгоритму и эффективности таких детектов как правило не выставляется.

      Борьба с потенциальным фродом это всегда статистика и 100%-й эффективности не достичь. А далее вступает в силу требования по уровню операционных рисков, потреь, резервирования и т.п. Так система и работает.


      1. daniilpashin
        21.09.2023 12:43

        Да я и не против таких требований, в общем-то, поэтому и написал в постскриптуме :). Мои претензии касаются скорее весьма низкого уровня исследования реализуемой области. Взять код 10-летней давности, надеяться, что он идеально работает, да еще и про это написать на хабре целую статью - извините, но уж лучше ничего тогда не писать.

        В противовес могу привести статью из предыдущего моего комментария. Человек, в основном не работающий с iOS, детально и по полочкам разобрал весь принцип обнаружения рута/джейлбрейка в Snapchat. Полноценно провел настоящее исследования и убедился, что его метод обхода детекта работает. Вот если бы подобное было озвучено в текущей статье - вопросов бы не было от слова совсем.