Android In App Billing: обеспечение открытого ключа приложения

От приложения Android In App Billing версии 3 (TrivialDrive) с приложением sdk

MainActivity.java

/* base64EncodedPublicKey should be YOUR APPLICATION PUBLIC KEY
 * (that you got from the Google Play developer console). This is not your
 * developer public key, it the *app-specific* public key.
 *
 * Instead of just storing the entire literal string here embedded in the
 * program,  construct the key at runtime from pieces or
 * use bit manipulation (for example, XOR with some other string) to hide
 * the actual key.  The key itself is not secret information, but we don't
 * want to make it easy for an attacker to replace the public key with one
 * of their own and then fake messages from the server.
 */
String base64EncodedPublicKey = "CONSTRUCT_YOUR_KEY_AND_PLACE_IT_HERE";

Ну, я не уверен, что понимаю эту меру безопасности. Я знаю, как получить открытый ключ приложения (который уже закодирован в базе 64) из консоли разработчика Google Play.

То, что я не понимаю, это эта часть

 /* Instead of just storing the entire literal string here embedded in the
 * program,  construct the key at runtime from pieces or
 * use bit manipulation (for example, XOR with some other string) to hide
 * the actual key
 */

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

Как мы можем создать один и тот же ключ программно, используя любой процесс манипуляции бит? Кто-то сделал это раньше? Есть ли какой-нибудь пример кода, как это сделать?

Ответ 1

Что-то вроде этого:

String Base64EncodedPublicKey key = "Ak3jfkd" + GetMiddleBit() + "D349824";

или

String Base64EncodedPublicKey key = 
         DecrementEachletter("Bl4kgle") + GetMiddleBit() + ReverseString("D349824");

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

Это не особенно хороший способ защитить ключ. Но он защищает от тривиальной атаки, когда кто-то просто ищет через буквальные строки в вас APK ищет что-то похожее на открытый ключ, основанный на base64. По крайней мере, вы делаете # $# $ers работы немного.

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

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

Предполагается, что любой, кто делает это, зарабатывает на жизнь 20 или 30 000 приложений для Android и переиздает их. Скорее всего, я полагаю, что они не собираются делать дополнительные десять минут, чтобы добавить ваше приложение в список из 20 000 приложений Android, которые уже были нарушены программой, если им действительно нужно немного поработать вручную. Если у вас нет приложения верхнего уровня. И тогда битва потенциально бесконечна и, вероятно, в конечном счете бесполезна.

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

Ответ 2

Альтернативой является выполнение некоторых основных преобразований на ключе.

// Replace this with your encoded key.
String base64EncodedPublicKey = "";

// Get byte sequence to play with.
byte[] bytes = base64EncodedPublicKey.getBytes();

// Swap upper and lower case letters.
for (int i = 0; i < bytes.length; i++) {
    if(bytes[i] >= 'A' && bytes[i] <= 'Z')
        bytes[i] = (byte)( 'a' + (bytes[i] - 'A'));
    else if(bytes[i] >= 'a' && bytes[i] <= 'z')
        bytes[i] = (byte)( 'A' + (bytes[i] - 'a'));
}

// Assign back to string.
base64EncodedPublicKey = new String( bytes );

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

Это, очевидно, довольно простой транскод, но вы можете быть более креативным, отменить порядок A-Z, обменять нечетные и четные числа, обменять гласные на четные числа. Проблема здесь в том, что если я добавлю код в приведенный выше фрагмент, который сделает кучу более интересных транскодов, а затем все будут копировать и вставлять их в свои проекты, взломщик будет легко видеть и использовать сам транскод (от просмотра эта почта)! Поэтому вам просто нужно придумать несколько преобразований.

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

Ответ 3

Вы можете разбить его на куски, как это

String piece1 = "SDFGJKGB4UIH234WE/FRT23RSDF/3DFUISDFVWE";
String piece2 = "SDFGJKGB4UIHUISDFVWE";
String piece3 = "BDYASGBDNAWGRET24IYE23das4saGBENWKD";
String piece4 = "432423SDF23R/+SDDS";

mHelper = new IabHelper(this, piece1 + piece2 + piece3 + piece4);

Любые манипуляции будут делать.

Вы не можете полностью скрыть открытый ключ от злоумышленника, вам просто нужно манипулировать строкой, чтобы немного запутать злоумышленника

Вы можете добавить некоторые строки и удалить их, когда это необходимо, или разделить на куски.

Ответ 4

То, что я сделал, - это преобразовать ключ в массив char, разбить его на две части и затем восстановить его при необходимости следующим образом:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_shop);

    char[] base64KeyByteArray = ArrayUtils.addAll(getPublicKeyChunk1(), getPublicKeyChunk2());

    Log.d(TAG, String.valueOf(base64KeyByteArray));
}

private char[] getPublicKeyChunk1() {
    return new char[]{82, 73, 67, 66, 73, 106, 65, 78, 66, 103, 107, 113, 104, 107,
            105, 71, 57, 119, 79, 66, 65, 81, 69, 70, 65, 65, 79, 67, 65, 81, 56, 65, 77, 73,
            73, 66, 67, 103, 75, 67, 65, 81, 69, 65, 121, 55, 81, 76, 122, 67, 105, 80, 65,
            110, 105, 101, 72, 66, 53, 57};
}

private char[] getPublicKeyChunk2() {
    return new char[]{82, 43, 68, 47, 79, 121, 122, 110, 85, 67, 118, 89, 108, 120, 43, 49,
            80, 100, 67, 108, 55, 90, 57, 103, 119, 57, 87, 78, 79, 111, 53, 101, 80, 71,
            117, 74, 104, 82, 87, 97, 100};
}

Ответ 5

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

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

Ответ 6

Кому действительно нужен секретный ключ? Я думаю, что вся идея заменить. ИМХО любые манипуляции бесполезны. Единственное, что нужно сделать злобному человеку, - это просто инициализировать переменную с правильным значением (его собственным ключом), которое одна строка вышла за вызов API Google.