Android, как обфускать статические константы строки? [Дубликат]

Если вы отправляете этот почтовый запрос в кросс-домен, вы должны проверить эту ссылку.

https://stackoverflow.com/a/1320708/969984

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

251
задан Basic Coder 3 February 2018 в 08:40
поделиться

14 ответов

  1. Как это, ваше скомпилированное приложение содержит ключевые строки, но также имена констант APP_KEY и APP_SECRET. Извлечение ключей из такого самодокументирующего кода тривиально, например, со стандартным инструментом Android dx.
  2. Вы можете применить ProGuard. Он оставит ключевые строки нетронутыми, но он удалит постоянные имена. Он также переименует классы и методы с короткими бессмысленными именами, где это возможно. Извлечение ключей затем занимает больше времени, чтобы выяснить, какая строка служит для этой цели. Обратите внимание, что настройка ProGuard не должна быть такой сложной, как вы боитесь. Для начала вам нужно включить ProGuard, как описано в project.properties. Если есть проблемы с сторонними библиотеками, вам может потребоваться подавить некоторые предупреждения и / или предотвратить их запутывание в proguard-project.txt. Например:
    -dontwarn com.dropbox.**
    -keep class com.dropbox.** { *; }
    
    Это подход грубой силы; вы можете уточнить такую ​​конфигурацию, как только обработанное приложение будет работать.
  3. Вы можете запутать строки вручную в своем коде, например, с кодировкой Base64 или предпочтительно с чем-то более сложным; возможно, даже собственный код. Затем хакеру придется статически реконструировать вашу кодировку или динамически перехватить декодирование в нужном месте.
  4. Вы можете применить коммерческий обфускатор, например, специализированный sigling ProGuard DexGuard . Он может дополнительно шифровать / обфускации строк и классов для вас. Извлечение ключей потребует еще большего времени и опыта.
  5. Возможно, вы сможете запускать части своего приложения на своем собственном сервере. Если вы можете хранить ключи там, они безопасны.

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

(я разработчик ProGuard и DexGuard)

266
ответ дан Eric Lafortune 16 August 2018 в 02:27
поделиться
  • 1
    Является ли это локальным сервером, о котором говорят в пятом пункте? Разве это не понадобится компьютеру, который должен постоянно оставаться? Извините, я новичок. Могу ли я использовать что-то вроде Parse? – user 5 June 2015 в 18:25
  • 2
    @EricLafortune не имеет значения, если строка частного ключа хранится в классе Java vs в XML-ресурсе String? – Alan 15 April 2016 в 16:16
  • 3
    @EricLafortune Теперь можно использовать систему Android Keystore для безопасного хранения ключей? ( developer.android.com/training/articles/keystore.html ) – David Thomas 29 April 2016 в 06:09
  • 4
    @DavidThomas: Вы пытались использовать хранилище ключей. Я хочу обфускать ключ API, написанный на Java-классе. ответьте, пожалуйста – Sagar Trehan 14 July 2016 в 05:49
  • 5
    Является ли Android KeyStore полезным для этого? ( developer.android.com/training/articles/… [/ д0]) – Weishi Zeng 22 August 2016 в 21:28

Старая старая почта, но все же достаточно хорошая. Я думаю, что скрывать его в библиотеке .so было бы здорово, конечно, используя NDK и C ++. .so файлы можно просмотреть в шестнадцатеричном редакторе, но удача декомпилирует: P

5
ответ дан Ahmed Awad 16 August 2018 в 02:27
поделиться
  • 1
    Пользователи могут легко выполнять вызовы функций в разделяемой библиотеке и получать там все, что скрывается. Не нужно его декомпилировать. – david72 3 November 2016 в 19:14
  • 2
    Согласно androidauthority.com/… нет безопасного способа сделать это в Android сейчас. – david72 3 November 2016 в 20:26
  • 3
    @AhmedAwad Не понимаю, почему у этого есть 3 upvote. любой может легко декомпилировать приложение и посмотреть, как вызывается точка входа ndk: / – Johny19 8 January 2017 в 16:16
  • 4
    Этот ответ является почти одним из лучших вариантов, но автор должен упомянуть, что очень важно, чтобы вы включили вызов (внутри вашей библиотеки NDK), чтобы проверить, соответствует ли контрольная сумма вашей APK, поскольку в противном случае кто-то может вызвать вашу библиотеку NDK за пределами ваше приложение – Sniper 26 November 2017 в 00:34
  • 5
    @Sniper, что было бы здорово, за исключением того, что у него большая проблема. Откуда вы знаете, что такое «вызов»? собственный метод? Если вы жестко скопируете имя apk, чтобы проверить, отлично, но что, если я сделаю свой «взломать»? apk в той же папке, что и «хорошая». APK? Он будет проверять, что "хороший" apk имеет хорошую контрольную сумму, и это позволит мне выполнить этот собственный метод. Если есть способ узнать файл вызывающего абонента со стороны JNI / C ++, то это бессмысленно, как и другие параметры. – SocketByte 1 July 2018 в 16:26

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

6
ответ дан Bernard Igiri 16 August 2018 в 02:27
поделиться
  • 1
    Проблема в том, что для достижения этого сервера, который содержит все секреты, я должен использовать другой секретный ключ. Интересно, где я это сохраню? ;) То, что я пытаюсь сказать, - это тоже не лучшее решение (не думайте, что здесь есть идеальное решение) – Mercury 26 January 2017 в 14:30
  • 2
    Это неправда, ваш сервер полностью находится под вашим контролем. То, что требуется, полностью зависит от вас. – Bernard Igiri 27 January 2017 в 11:24
  • 3
    Можете ли вы объяснить, как клиент может шифровать данные, которые он хочет отправить на сервер, а ключи находятся на стороне сервера? и если ваш ответ будет - сервер отправляет ключи клиенту - так что это необходимо также обеспечить! так что снова не волшебное решение! разве ты не видишь ?! – Mercury 2 February 2017 в 21:42
  • 4
    @BernardIgiri, а затем снова вернемся к квадрату 1. Предположим, телефон создает случайный логин, и сервер принимает это и отправляет булавку (это так называемый закрытый сервер , который мы говорим). Затем человек, который разбирает ваше приложение, видит, что все, что требуется для доступа к вашему частному серверу, - это просто случайный логин, который он может создать самостоятельно. Скажите, что мешает ему создать его и получить доступ к вашему серверу? На самом деле в чем разница между вашим решением и фактическим хранением ключа входа или api на главный сервер (чьи учетные данные мы хотели сохранить на нашем частном сервере) – Ken 4 March 2017 в 10:15
  • 5
    @ken Случайное число аутентифицируется по номеру телефона и физическому доступу к его текстовым сообщениям. Если кто-то обманывает вас, у вас есть информация. Если это недостаточно, заставьте их создать полную учетную запись пользователя и пароль. Если это не достаточно, получите кредитную карту. Если этого недостаточно, им нужно позвонить. Если это не достаточно хорошо встретить их лицом к лицу. Насколько вы безопасны / неудобны? – Bernard Igiri 8 March 2017 в 15:01

Немного идей, на мой взгляд, только первый дает некоторую гарантию:

  1. Храните свои секреты на каком-то сервере в Интернете, а когда нужно, просто возьмите их и используйте. Если пользователь собирается использовать dropbox, ничто не мешает вам делать запрос на ваш сайт и получать секретный ключ.
  2. Поместите свои секреты в jni-код, добавьте некоторый переменный код, чтобы сделать ваши библиотеки большими и сложными декомпилировать. Вы также можете разделить ключевую строку на несколько частей и сохранить их в разных местах.
  3. использовать obfuscator, также помещать в код хэшированный секрет, а затем разжать его, когда нужно использовать.
  4. Поместите свой секретный ключ в качестве последних пикселей одного из ваших изображений в активах. Затем, когда это необходимо, прочитайте его в своем коде.

Если вы хотите быстро взглянуть на то, как легко читать код apk, а затем захватить APKAnalyser:

http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/

56
ответ дан marcinj 16 August 2018 в 02:27
поделиться
  • 1
    если пользователь может декомпилировать приложение, хотя они могли бы определить запрос, который был сделан на ваш собственный сервер, и просто выполнить это, чтобы получить секрет. Здесь нет серебряной пули, но сделайте несколько шагов, и я готов поспорить, что все будет хорошо! Если ваше приложение очень популярно, возможно, нет. Отличные идеи! – Matt Wolfe 28 January 2013 в 23:11
  • 2
    да, номер 1 не дает никакой гарантии. – marcinj 28 January 2013 в 23:34
  • 3
    Мне очень нравится идея скрывать ключи внутри изображений. +1 – PSIXO 30 January 2014 в 16:24
  • 4
    @ MarcinJędrzejewski Вы хотели бы объяснить больше (например, с образцом или отрывом кода) о четвертом решении? Спасибо. – Mr.Hyde 16 April 2016 в 05:53
  • 5
    @ Mr.Hyde это называется стеганография, ее слишком сложная задача, чтобы дать пример кода здесь, вы можете найти примеры в google. Я нашел его здесь: dreamincode.net/forums/topic/27950-steganography . Идея замечательная, но поскольку код apk можно декомпилировать, это портит ее красоту. – marcinj 21 April 2016 в 21:46

Одним из возможных решений является кодирование данных в вашем приложении и использование декодирования во время выполнения (когда вы хотите использовать эти данные). Я также рекомендую использовать progaurd, чтобы затруднить чтение и понимание декомпилированного исходного кода вашего приложения. например, я поместил закодированный ключ в приложение, а затем использовал метод декодирования в своем приложении для декодирования моих секретных ключей во время выполнения:

// "the real string is: "mypassword" "; 
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
    return Utils.decode(Utils
            .decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}

Декомпилированный исходный код защищенного приложения:

 public String c()
 {
    return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
  }

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

/**
 * @param input
 * @return decoded string
 */
public static String decode(String input) {
    // Receiving side
    String text = "";
    try {
        byte[] data = Decoder.decode(input);
        text = new String(data, "UTF-8");
        return text;
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return "Error";
}

Декомпилированная версия:

 public static String a(String paramString)
  {
    try
    {
      str = new String(a.a(paramString), "UTF-8");
      return str;
    }
    catch (UnsupportedEncodingException localUnsupportedEncodingException)
    {
      while (true)
      {
        localUnsupportedEncodingException.printStackTrace();
        String str = "Error";
      }
    }
  }

, и вы можете найти так много классов шифрования с небольшим искать в google.

8
ответ дан Milad Faridnia 16 August 2018 в 02:27
поделиться

Единственный верный способ сохранить эти личные данные - сохранить их на своем сервере и отправить приложение на сервер, а сервер взаимодействует с Dropbox. Таким образом, вы НИКОГДА не распространяете свой закрытый ключ в любом формате.

1
ответ дан Nick 16 August 2018 в 02:27
поделиться
  • 1
    Но как вы запрещаете всему миру звонить на сервер? – user2966445 8 September 2016 в 01:52
  • 2
    Если по "серверу" вы имеете в виду ваш веб-сервер, где находятся учетные данные, - вы можете использовать любой метод, который вы хотите. простая аутентификация с именем пользователя / паролем, oauth, активным каталогом и т. д. и т. д. Действительно зависит от вашего приложения. – Nick 8 September 2016 в 14:04
  • 3
    Может быть, мне что-то не хватает, но разве это не требует хранения учетных данных в приложении? – user2966445 8 September 2016 в 21:59
  • 4
    Правильно, но вы сказали, что приложение будет сначала аутентифицироваться на сервере. Разве это не означает сохранение другого набора учетных данных в приложении? Я понимаю, что сервер будет обрабатывать фактические вызовы Dropbox. – user2966445 9 September 2016 в 02:22
  • 5
    Ну, это может означать это, но это совершенно отдельная авторизация. Но вам это не нужно. Я говорю о том, что пользователь вашего приложения будет иметь доступ к вашему приложению, скажем, используя facebook или twitter. Вы не храните свои учетные данные в своем приложении, вы даже не знаете их. Этот процесс авторизации позволяет им получить доступ к вашему серверу api, который имеет учетные данные для Dropbox, но ни одно приложение или пользователь не имеют к ним доступ напрямую. – Nick 9 September 2016 в 14:00

Сохраните секрет в firebase database и получите от него при запуске приложения. Это намного лучше, чем вызов веб-службы.

1
ответ дан Redman 16 August 2018 в 02:27
поделиться
  • 1
    но как насчет учетных данных для firebase? – the_joric 28 March 2018 в 15:14
  • 2
    К сожалению, база данных Firebase не работает в Китае. – Konjengbam 23 April 2018 в 17:31
  • 3
    не имеет смысла, злоумышленники могут видеть ваши детали firebase из декомпилированного кода и получать любые данные из вашего datababse – user924 6 May 2018 в 10:09
  • 4
    – Ayman Al-Absi 12 September 2018 в 22:09

Следуйте 3 простым шагам по защите ключа API / Secret

Мы можем использовать Gradle для защиты ключа API или секретного ключа.

1. gradle.properties (Свойства проекта): Создать переменную с ключом.

GoolgeAPIKey = "Your API/Secret Key"

2. build.gradle (Module: app): установите переменную в build.gradle для доступа к ней в активности или фрагменте. Добавьте ниже код в buildTypes {}.

buildTypes.each {
    it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}

3. Получите доступ к нему в Activity / Fragment с помощью приложения BuildConfig:

BuildConfig.GoogleSecAPIKEY

Обновление:

Вышеупомянутое решение полезно в проекте с открытым исходным кодом для передачи по Git. (Спасибо Дэвиду Роусону и Риязи-Али за ваш комментарий).

Согласно комментариям Мэтью и Пабло Чегарры, вышеупомянутый способ небезопасен, и Декомпилятор позволит кому-то просмотреть BuildConfig с помощью наших секретных ключей.

Решение:

Мы можем использовать NDK для защиты API-ключей. Мы можем хранить ключи в собственном классе C / C ++ и обращаться к ним в наших классах Java.

Пожалуйста, следуйте этому блоку , чтобы защитить ключи API с помощью NDK.

Последующее наблюдение за тем, как безопасно хранить маркеры в Android

19
ответ дан SANAT 16 August 2018 в 02:27
поделиться
  • 1
    сохранение ключа в файле градации безопасно? – Google 4 December 2017 в 09:26
  • 2
    @Google gradle.properties не следует указывать в Git, поэтому это способ сохранить секрет из совершенного исходного кода, по крайней мере – David Rawson 9 December 2017 в 10:40
  • 3
    Это не препятствует объединению API-ключа в результирующий apk (он будет добавлен в сгенерированный файл BuildConfig), хотя это определенно хорошая идея для управления различными ключами API (например, с открытым исходным кодом проект) – riyaz-ali 8 March 2018 в 09:07
  • 4
    Использование Java Decompiler позволит кому-то просмотреть файл BuildConfig и «GoogleSecAPIKEY». – Matthew 13 March 2018 в 19:57
  • 5
    действительно 11 upvotes? просто декомпилировать, открыть строки и voilá – Pablo Cegarra 23 April 2018 в 22:25

Другой подход заключается в том, чтобы не иметь секрет на устройстве в первую очередь! См. Методы безопасности мобильных API (особенно часть 3).

Используя традиционную косвенную традицию, поделитесь секретом между конечной точкой API и службой проверки подлинности приложения. Когда ваш клиент хочет вызвать вызов API, он просит службу аутентификации приложения аутентифицировать его (используя сильные методы удаленной аттестации) и получает ограниченный по времени (обычно JWT) токен, подписанный этим секретом. Маркер отправляется с каждым вызовом API, где конечная точка может проверить свою подпись перед действием по запросу.

Настоящий секрет никогда не присутствует на устройстве; на самом деле, приложение никогда не знает, действительно ли оно или нет, оно вызывает проверку подлинности и передает полученный результирующий токен.

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

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

4
ответ дан Skip Hovsmith 16 August 2018 в 02:27
поделиться

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

Защита секретности в пути

Первое, что нужно отметить, это доступ к API-интерфейсу Dropbox с использованием их механизм аутентификации приложений требует, чтобы вы передавали свой ключ и секрет. Соединение HTTPS означает, что вы не можете перехватить трафик, не зная сертификата TLS. Это делается для того, чтобы человек не перехватывал и не читал пакеты на своем пути с мобильного устройства на сервер. Для обычных пользователей это действительно хороший способ обеспечить конфиденциальность своего трафика.

То, на что это не удобно, мешает злоумышленнику загружать приложение и проверять трафик. Очень просто использовать прокси-сервер man-in-the-middle для всего трафика на мобильном устройстве и из него. Это не требует разборки или обратного проектирования кода, чтобы извлечь ключ приложения и секрет в этом случае из-за характера API Dropbox.

Вы могли бы выполнить pinning , который проверяет, что сертификат TLS, который вы получаете с сервера, является тем, который вы ожидаете. Это добавляет проверку клиенту и затрудняет перехват трафика. Это затруднило бы проверку трафика в полете, но проверка пиннинга происходит в клиенте, поэтому, вероятно, по-прежнему можно будет отключить тест пиннинга.

Защита секретности в покое

Как первый шаг, использование чего-то вроде proguard поможет сделать его менее очевидным, если любые секреты. Вы также можете использовать NDK для хранения ключа и секретности и отправки запросов напрямую, что значительно сократит количество людей с соответствующими навыками для извлечения информации. Дальнейшая обфускация может быть достигнута за счет сохранения значений непосредственно в памяти в течение какого-то времени, вы можете зашифровать их и дешифровать их непосредственно перед использованием, как предложено другим ответом.

Дополнительные параметры

Если вы сейчас параноик о том, чтобы хранить секрет в своем приложении, и у вас есть время и деньги, чтобы инвестировать в более комплексные решения, вы можете подумать о сохранении учетных данных на своих серверах (предположительно, что у вас есть). Это увеличило бы латентность любых вызовов API, поскольку оно должно будет связываться через ваш сервер и может увеличить затраты на обслуживание вашего сервиса из-за увеличения пропускной способности данных.

Затем вам нужно решить, как лучше всего общаться с серверами, чтобы обеспечить их защиту. Это важно для предотвращения повторения всех тех же проблем с вашим внутренним API. Лучшее эмпирическое правило, которое я могу дать, - это не передавать какой-либо секрет напрямую из-за угрозы «человек-в-середине». Вместо этого вы можете подписывать трафик, используя свой секрет, и проверять целостность любых запросов, поступающих на ваш сервер. Один из стандартных способов сделать это - вычислить HMAC сообщения, заключенного в секрет. Я работаю в компании, у которой есть продукт безопасности, который также работает в этой области, поэтому меня интересуют такие вещи. Фактически, вот статья blog от одного из моих коллег, который использует большую часть этого.

Сколько я должен делать?

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

7
ответ дан ThePragmatist 16 August 2018 в 02:27
поделиться

Ключ App-Secret должен оставаться закрытым - но при выпуске приложения они могут быть отменены некоторыми ребятами.

для этих парней он не скрывает, блокирует либо код ProGuard. Это рефактор, и некоторые платные обфускаторы вставляют несколько побитовых операторов, чтобы вернуть строку jk433g34hg3. Вы можете сделать 5-15 минут дольше взлома, если вы работаете 3 дня:)

Лучший способ сохранить это как есть, imho.

Даже если вы храните на стороне сервера (ваш ПК), ключ может быть взломан и распечатан. Может быть, это занимает больше всего времени? Во всяком случае, это всего лишь несколько минут или несколько часов в лучшем случае.

Обычный пользователь не декомпилирует ваш код.

10
ответ дан user 16 August 2018 в 02:27
поделиться
  • 1
    Ну - не ответ, который я надеялся получить =) ... Я думал, что вы можете добиться большой безопасности :( – Basic Coder 28 January 2013 в 22:57
  • 2
    жаль, что это не так, как вам хотелось бы блестящего, сверхбезопасного решения, но для тех, кто может использовать компилятор, декомпилятор не содержит безопасного кода Java: даже собственный код можно просмотреть с помощью hexa viewer и decrtyped. По крайней мере стоит попробовать ... – user 28 January 2013 в 22:58
  • 3
    Proguard не будет запутывать фактический ключ, хотя ..? Самое лучшее, что нужно сделать, это простая процедура шифрования / дешифрования, которая сглаживает скрыть. – Doomsknight 28 January 2013 в 23:05
  • 4
    он вл етс "видимым" процедура дешифрования, легко сделать обратное, и у вас есть исходная строка – user 28 January 2013 в 23:06

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

Поэтому, если пользователь не вводит ПИН или фразу, нет способа скрыть ключ. Но для этого вам нужно будет иметь схему управления PIN-кодом, происходящим вне диапазона, а это означает, что с помощью другого канала. Конечно, это не практично для обеспечения ключей для таких сервисов, как API Google.

3
ответ дан user1611728 16 August 2018 в 02:27
поделиться
0
ответ дан Ayman Al-Absi 29 October 2018 в 08:20
поделиться
0
ответ дан RonTLV 29 October 2018 в 08:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: