String myCertHash(Context context)
{
if (sMyCertHash == null) {
if (Utils.isDebuggable(context)) {
// значение хэша сертификата "androiddebugkey" в debug.keystore.
sMyCertHash = "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255";
} else {
// значение хэша сертификата «my company key» в keystore.
sMyCertHash = "D397D343 A5CBC10F 4EDDEB7C A10062DE 5690984F 1FB9E88B D7B3A7C2 42E142CA";
}
}
return sMyCertHash;
}
@Override
public boolean onCreate() {
return true;
}
@Override
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case DOWNLOADS_CODE:
case ADDRESSES_CODE:
return CONTENT_TYPE;
case DOWNLOADS_ID_CODE:
case ADDRESSES_ID_CODE:
return CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Invalid URI:" + uri);
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// *** POINT 4 *** Проверьте, определено ли разрешение на подпись от внутреннего приложения.
if (!SigPerm.test(getContext(), MY_PERMISSION, myCertHash(getContext()))) {
throw new SecurityException("Разрешение на внутреннюю подпись не объявлено внутренним приложением.");
}
// *** POINT 5 *** Обрабатывайте полученные данные запроса осторожно и безопасно,
// даже если данные поступили от внутреннего приложения.
// Здесь соответствие uri ожиданиям проверяется с помощью UriMatcher#match() и switch case.
// Проверка других параметров здесь опущена из-за примера.
// См. «3.2 Осторожно и безопасно обрабатывайте входные данные».
// *** POINT 6 *** Может быть возвращена конфиденциальная информация, поскольку запрашивающее приложение является внутренним.
// Смысл результата запроса зависит от приложения.
switch (sUriMatcher.match(uri)) {
case DOWNLOADS_CODE:
case DOWNLOADS_ID_CODE:
return sDownloadCursor;
case ADDRESSES_CODE:
case ADDRESSES_ID_CODE:
return sAddressCursor;
default:
throw new IllegalArgumentException("Неверный URI:" + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// *** POINT 4 *** Убедитесь, что разрешение на внутреннюю подпись определено внутренним приложением.
if (!SigPerm.test(getContext(), MY_PERMISSION, myCertHash(getContext()))) {
throw new SecurityException("Разрешение на внутреннюю подпись не заявлено внутренним приложением.");
}
// *** POINT 5 *** Обращайтесь с полученными данными запроса осторожно и безопасно,
// несмотря на то, что данные поступили из внутреннего приложения.
// Соответствие uri ожиданиям здесь проверяется с помощью UriMatcher#match() и switch case.
// Другие параметры здесь не проверяются из-за образца.
// Обратитесь к разделу «3.2 Обрабатывать входные данные осторожно и безопасно».
// *** POINT 6 *** Конфиденциальная информация может быть возвращена, так как запрашивающее приложение внутреннее.
// Это зависит от приложения, имеет ли выданный ID конфиденциальное значение или нет.
switch (sUriMatcher.match(uri)) {
case DOWNLOADS_CODE:
return ContentUris.withAppendedId(Download.CONTENT_URI, 3);
case ADDRESSES_CODE:
return ContentUris.withAppendedId(Address.CONTENT_URI, 4);
default:
throw new IllegalArgumentException("Неверный URI:" + uri);
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// *** POINT 4 *** Убедитесь, что разрешение на внутреннюю подпись определено
В запросе отсутствует перевод фрагмента кода. Данный фрагмент написан на языке Java.
Текст описывает процесс проверки разрешения на доступ к данным в приложении, а также обработку запросов на получение и удаление данных.
В тексте проверяется наличие определённого разрешения у приложения, которое запрашивает данные. Если разрешение не определено, то генерируется исключение. Затем происходит обработка запроса с использованием метода UriMatcher#match() и switch case. В зависимости от типа запроса возвращается соответствующее значение.
Также в тексте упоминается, что приложение может возвращать чувствительную информацию, и это зависит от конкретного приложения.
Обратите внимание, что данный текст может содержать ошибки или неточности перевода. (NameNotFoundException e) { return null; }
PkgCert.java
```java
package org.jssec.android.shared;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
public class PkgCert {
public static boolean test(Context ctx, String pkgname, String correctHash) {
if (correctHash == null) return false;
correctHash = correctHash.replaceAll(" ", "");
return correctHash.equals(hash(ctx, pkgname));
}
public static String hash(Context ctx, String pkgname) {
if (pkgname == null) return null;
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pkginfo = pm.getPackageInfo(pkgname, PackageManager.GET_SIGNATURES);
if (pkginfo.signatures.length != 1) return null; // Will not handle multiple signatures.
Signature sig = pkginfo.signatures[0];
byte[] cert = sig.toByteArray();
byte[] sha256 = computeSha256(cert);
return byte2hex(sha256);
} catch (NameNotFoundException e) {
return null;
}
}
private static byte[] computeSha256(byte[] data) {
try {
return MessageDigest.getInstance("SHA-256").digest(data);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
private static String byte2hex(byte[] data) {
if (data == null) return null;
final StringBuilder hexadecimal = new StringBuilder();
for (final byte b : data) {
hexadecimal.append(String.format("%02X", b));
}
return hexadecimal.toString();
}
}
Важно: 7 — при экспорте APK используйте тот же ключ разработчика для подписи APK.
Изображение:
Использование внутреннего поставщика контента.
Важные моменты:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jssec.android.provider.inhouseuser">
<!-- *** POINT 8 *** Declare to use the in-house signature permission. -->
<uses-permission
android:name="org.jssec.android.provider.inhouseprovider.MY_PERMISSION" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".InhouseUserActivity"
android:label="@string/app_name"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
InhouseUserActivity.java
package org.jssec.android.provider.inhouseuser;
import org.jssec.android.shared.PkgCert;
import org.jssec.android.shared.SigPerm;
import org.jssec.android.shared.Utils;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class InhouseUserActivity extends Activity {
// Target Content Provider Information
private static final String AUTHORITY = "org.jssec.android.provider.inhouseprovider";
private interface Address {
public static final String PATH = "addresses";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH);
}
// In-house Signature Permission
private static final String MY_PERMISSION = "org.jssec.android.provider.inhouseprovider.MY_PERMISSION";
//
``` Значение хэша сертификата
private static String sMyCertHash = null;
private static String myCertHash(Context context) {
if (sMyCertHash == null) {
if (Utils.isDebuggable(context)) {
// Значение хэша сертификата "androiddebugkey" в debug.keystore.
sMyCertHash = "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255";
} else {
// Значение хэша сертификата «ключа компании» в keystore.
sMyCertHash = "D397D343 A5CBC10F 4EDDEB7C A10062DE 5690984F 1FB9E88B D7B3A7C2 42E142CA";
}
}
return sMyCertHash;
}
// Получить имя пакета целевого поставщика контента.
private static String providerPkgname(Context context, Uri uri) {
String pkgname = null;
PackageManager pm = context.getPackageManager();
ProviderInfo pi = pm.resolveContentProvider(uri.getAuthority(), 0);
if (pi != null) pkgname = pi.packageName;
return pkgname;
}
public void onQueryClick(View view) {
logLine("[Query]");
// *** ТОЧКА 9 *** Убедитесь, что разрешение на подпись от имени компании определено приложением от компании.
if (!SigPerm.test(this, MY_PERMISSION, myCertHash(this))) {
logLine(" Разрешение на подпись от имени компании не объявлено приложением от компании.");
return;
}
// *** ТОЧКА 10 *** Убедитесь, что целевое приложение подписано сертификатом от компании.
String pkgname = providerPkgname(this, Address.CONTENT_URI);
if (!PkgCert.test(this, pkgname, myCertHash(this))) {
logLine(" Целевой поставщик контента не обслуживается приложениями от компании.");
return;
}
Cursor cursor = null;
try {
// *** ТОЧКА 11 *** Можно отправлять конфиденциальную информацию, поскольку целевое приложение является внутренним.
cursor = getContentResolver().query(Address.CONTENT_URI, null, null, null, null);
// *** ТОЧКА 12 *** Обрабатывайте полученные данные осторожно и безопасно,
// даже если данные поступают из внутреннего приложения.
// Опущено, так как это пример. Пожалуйста, обратитесь к разделу «3.2. Обработка данных с осторожностью и безопасностью».
if (cursor == null) {
logLine(" нулевой курсор");
} else {
boolean moved = cursor.moveToFirst();
while (moved) {
logLine(String.format(" %d, %s", cursor.getInt(0), cursor.getString(1)));
moved = cursor.moveToNext();
}
}
} finally {
if (cursor != null) cursor.close();
}
}
public void onInsertClick(View view) {
logLine("[Insert]");
// *** ТОЧКА 9 *** Убедитесь, что разрешение на подпись от имени компании определено приложением от компании.
String correctHash = myCertHash(this);
if (!SigPerm.test(this, MY_PERMISSION, correctHash)) {
logLine(" Разрешение на подпись от имени компании не объявлено приложением от компании.");
return;
}
// *** ТОЧКА 10 *** Убедитесь, что целевое приложение подписано сертификатом от компании.
String pkgname = providerPkgname(this, Address.CONTENT_URI);
if (!PkgCert.test(this, pkgname, correctHash)) {
logLine(" Целевой поставщик контента не обслуживается приложениями от компании.");
return;
}
// *** ТОЧКА 11 *** Можно отправлять конфиденциальную информацию, поскольку целевое приложение является внутренним.
ContentValues values = new ContentValues();
values.put("city", "Tokyo");
Uri uri = getContentResolver().insert(Address.CONTENT_URI, values);
// *** ТОЧКА 12 *** Обрабатывайте полученные данные осторожно и безопасно,
// даже если данные поступают из внутреннего приложения.
// Опущено, так как это пример. Пожалуйста, обратитесь к разделу «3.2. Обработка данных с осторожностью и безопасностью». ПакэджМенеджер.ГЭТ_МЭТА_ДАТА);
Строка пкгнэйм = пи.пакетнэйм;
// Ошибка, если разрешение с именем сигПёрнэйм не является Сигнатурным Разрешением
если (пи.протэктионлэвэл != ПёрмишнИнфо.ПРОТЭКТИОН_СИГНАТУРА) вернуть ноль;
// Возвратить значение хэша сертификата приложения, которое объявляет разрешение с именем сигПёрнэйм.
вернуть ПкгСёрт.хэш(контекст, пкгнэйм);
}
поймать (НэймНотфаундИксэпшэн и) {
вернуть ноль;
}
}
PkgCert.java
пакет орг.джс сек.андроид.шаред;
импорт джава.сэкьюрити.МэссэджДигэст;
импорт джава.сэкьюрити.НоСачАлгоритэмИксэпшэн;
импорт андроид.контент.Контекст;
импорт андройд.контент.пм.ПакэджИнфо;
импорт андройд.контент.пм.ПакэджМэнеджер;
импорт андройд.контент.пм.НэймНотфэундИксэпшэн;
импорт андройд.контент.пм.Сигнатура;
публичный класс ПкгСёрт {
публичная статическая брэоуан тест(Контекст контекст, Строка пкгнэйм, Строка коррэктХэш) {
если (коррэкхтХэш == ноль) вернуть фэйлс;
коррэкхтХэш = коррэкхтХэш.рэплейсОлл(" ", "");
вернуть коррэкхтХэш.иквэлс(хэши(контекст, пкгнэйм));
}
публичный статический хэши(Контекст контекст, Строка пкгнэйм) {
если (пкгнэйм == ноль) вернуть ноль;
попробуй {
ПакэджМэнеджер пм = контекст.гэтуПакэджМэнеджер();
ПакэджИнфо пкгинфо = пм.гэтПакэджИнфо(пкгнэйм, ПакэджМэнеджер.ГЭТ_СИНГЭТЮРЭС);
если (пкгинфо.сингэтюрс.лэнхт != 1) вернуть ноль; // Не будет обрабатывать множественные подписи.
Сигнатура сиг = пкгинфо.сингэтюрс[0];
байт[] сирт = сиг.тоБайтАррэу();
байт[] ша256 = компутэШа256(сирт);
вернуть байт ту хэкс(ша256);
} поймать (НэймНотфэундИксэпшэн е) {
вернуть ноль;
}
}
приватный статический байт аррэу компутэШа256(байт[] данные) {
попробуй {
возвратить МэссэджДигэст.джинсэнс("ША-256").дайджест(данные);
} поймать (НоСачАлгоритэмИксэпшэн е) {
вернуть ноль;
}
}
приватная статическая строка байт ту хэкс(байт[] данные) {
если (данные == ноль) вернуть ноль;
финал СтракБилдер хэксэдэцимал = новый СтракБилдер();
для (финал байт б : данные) {
хэксэдэцимал.аппенд(стрэнг.формат("%02X", б));
}
вернуть хэксэдэцимал.тустрнг();
}
}
Надо отметить 13: при экспорте APK используйте тот же ключ разработчика для подписи APK, что и у запрашиваемого приложения.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )