1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-android-app-sec-guidebook

Клонировать/Скачать
4.3.1.5.md 16 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 27.11.2024 20:24 c13bfb7

Создание/использование временного контент-провайдера

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

Пример кода для реализации временного контент-провайдера:

  1. Явно установите для экспортируемого атрибута значение false.
  2. Используйте grant-uri-permission для указания пути для временного предоставления доступа.
  3. Даже если данные поступают от приложения, получающего временный доступ, следует безопасно обрабатывать полученные запросы данных.
  4. Можно возвращать информацию, открытую для приложений, получающих временный доступ.
  5. Укажите URI в намерении для предоставления временного доступа.
  6. Укажите права доступа в намерении для предоставления временного доступа.
  7. Отправьте явное намерение приложению для предоставления ему временного доступа.
  8. Верните намерение приложению, запросившему временный доступ.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.jssec.android.provider.temporaryprovider">
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".TemporaryActiveGrantActivity"
            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>
        <!-- Temporary Content Provider -->
        <!-- *** POINT 1 *** Explicitly set the exported attribute to false. -->
        <provider
            android:name=".TemporaryProvider"
            android:authorities="org.jssec.android.provider.temporaryprovider"
            android:exported="false" >
            <!-- *** POINT 2 *** Specify the path to grant access temporarily with the grant-uri-permissi
on. -->
            <grant-uri-permission android:path="/addresses" />
        </provider>
        <activity
        android:name=".TemporaryPassiveGrantActivity"
        android:label="@string/app_name"
        android:exported="true" />
    </application>
</manifest>

TemporaryProvider.java

package org.jssec.android.provider.temporaryprovider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;

public class TemporaryProvider extends ContentProvider {

    public static final String AUTHORITIY = "org.jssec.android.provider.temporaryprovider";
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.org.jssec.contenttype";
    public public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.org.jssec.contenttype";
    // Expose the interface that the Content Provider provides.
    
    public interface Download {
        public static final String PATH = "downloads";
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITIY + "/" + PATH);
    }
    
    public interface Address {
        public static final String PATH = "addresses";
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITIY + "/" + PATH);
    }
    
    // UriMatcher
    private static final int DOWNLOADS_CODE = 1;
    private static final int DOWNLOADS_ID_CODE = 2;
    private static final int ADDRESSES_CODE = 3;
    private static final int ADDRESSES_ID_CODE = 4;
    private static UriMatcher sUriMatcher;
    
    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(AUTHORITIY, Download.PATH, DOWNLOADS_CODE);
        sUriMatcher.addURI(AUTHORITIY, Download.PATH + "/#", DOWNLOADS_ID_CODE);
        sUriMatcher.addURI(AUTHORITIY, Address.PATH, ADDRESSES_CODE);
        sUriMatcher.addURI(AUTHORITIY, Address.PATH + "/#", ADDRESSES_ID_CODE);
    }
    
    // Since this is a sample program,
    // query method returns the following fixed result always without using database.
    private static MatrixCursor sAddressCursor = new MatrixCursor(new String[] { "_id", "city" });
    
    static {
        sAddressCursor.addRow(new String[] { "1", "New York" });
        sAddressCursor.addRow(new String[] { "2", "London" });
        sAddressCursor.addRow(new String[] { "3", "Paris" });
    }
    
    private static MatrixCursor sDownloadCursor = new

*Здесь текст обрывается.* Матричный курсор (новый массив {"_id", "path"});  

static {  
    sDownloadCursor.addRow(новый массив {"1", "/sdcard/downloads/sample.jpg"});  
    sDownloadCursor.addRow(новый массив {"2", "/sdcard/downloads/sample.txt"});  
}  

@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("Неверный URI:" + uri);  
    }  
}  

@Override  
public Cursor query(Uri uri, String[] projection, String selection,  
    String[] selectionArgs, String sortOrder) {  
    // *** ТОЧКА 3 *** Обрабатывайте полученные данные запроса осторожно и безопасно,  
    // даже если данные поступают из приложения, которому временно предоставлен доступ.  
    // Здесь проверяется, соответствует ли uri ожиданиям, с помощью UriMatcher#match() и switch case.  
    // Проверка других параметров здесь опущена из-за примера.  
    // Пожалуйста, обратитесь к разделу «3.2. Осторожная и безопасная обработка входных данных».  
    // *** ТОЧКА 4 *** Может быть возвращена информация, которая разрешена для раскрытия временным приложениям доступа.  
    // От приложения зависит, можно ли раскрывать результат запроса или нет.  
    switch (sUriMatcher.match(uri)) {  
        case DOWNLOADS_CODE:  
        case DOWNLOADS_ID_CODE:  
            вернуть sDownloadCursor;  
        case ADDRESSES_CODE:  
        case ADDRESSES_ID_CODE:  
            вернуть sAddressCursor;  
        default:  
            бросить новое исключение IllegalArgumentException («Неверный URI:» + uri);  
    }  
}  

@Override  
public Uri insert(Uri uri, ContentValues values) {  
    // *** ТОЧКА 3 *** Обрабатывайте полученные данные запроса осторожно и безопасно,  
    // даже если данные поступают из приложения, которому временно предоставлен доступ.  
    // Здесь проверяется, соответствует ли uri ожиданиям, с помощью UriMatcher#match() и switch case.  
    // Проверка других параметров здесь опущена из-за примера.  
    // Пожалуйста, обратитесь к разделу «3.2 Осторожная и безопасная обработка входных данных».  
    // *** ТОЧКА 4 *** Информация, которая разрешена к раскрытию временным приложениям доступа, может быть возвращена.  
    // Зависит от приложения, имеет ли выданный ID чувствительное значение или нет.  
    switch (sUriMatcher.match(uri)) {  
        case DOWNLOADS_CODE:  
            вернуть ContentUris.withAppendedId(Download.CONTENT_URI, 3);  
        case ADDRESSES_CODE:  
            вернуть ContentUris.withAppendedId(Address.CONTENT_URI, 4);  
        default:  
            бросить новое исключение IllegalArgumentException («Неверный URI:» + uri);  
    }  
}  

@Override  
public int update(Uri uri, ContentValues values, String selection,  
    String[] selectionArgs) {  
    // *** ТОЧКА 3 *** Обрабатывайте полученные данные запроса осторожно и безопасно,  
    // даже если данные поступают из приложения, которому временно предоставлен доступ.  
    // Здесь проверяется, соответствует ли uri ожиданиям, с помощью UriMatcher#match() и switch case.  
    // Проверка других параметров здесь опущена из-за примера.  
    // Пожалуйста, обратитесь к разделу «3.2 Осторожная и безопасная обработка входных данных».  
    // *** ТОЧКА 4 *** Информация, которая разрешена к раскрытию временным приложениям доступа, может быть возвращена.  
    // Зависит от приложения, имеет ли количество обновлённых записей чувствительное значение или нет.  
    switch (sUriMatcher.match(uri)) {  
        case DOWNLOADS_CODE:  
            вернуть 5; // Возвращает количество обновленных записей  
        case DOWNLOADS_ID_CODE:  
            вернуть 1;  
        case ADDRESSES_CODE:  
            вернуть 15;  
        case ADDRESSES_ID_CODE:  
            вернуть 1; **Вот перевод текста на русский язык:**

public void onCloseClick(View view) { finish(); } }


**Ниже приведён пример временного поставщика контента.**

*Важные моменты (использование поставщика контента):*

9. Не отправляйте конфиденциальную информацию.

10. Когда вы получаете результат, будьте осторожны и безопасно обрабатывайте данные результата.

TemporaryUserActivity.java

```java
package org.jssec.android.provider.temporaryuser;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
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 TemporaryUserActivity extends Activity {

    // Информация о действии поставщика временного контента.
    private static final String TARGET_PACKAGE = "org.jssec.android.provider.temporaryprovider";
    private static final String TARGET_ACTIVITY = "org.jssec.android.provider.temporaryprovider.TemporaryPassiveGrantActivity";
    // Целевая информация поставщика контента
    private static final String AUTHORITY = "org.jssec.android.provider.temporaryprovider";

    private interface Address {
        public static final String PATH = "addresses";
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH);
    }

    private static final int REQUEST_CODE = 1;

    public void onQueryClick(View view) {
        logLine("[Query]");
        Cursor cursor = null;
        try {
            if (!providerExists(Address.CONTENT_URI)) {
                logLine(" Поставщик контента не существует.");
                return;
            }
            // *** ТОЧКА 9 *** Не отправляйте конфиденциальную информацию.
            // Если нет проблем с тем, что информация будет получена вредоносным ПО, её можно включить в запрос.
            cursor = getContentResolver().query(Address.CONTENT_URI, null, null, null, null);
            // *** ТОЧКА 10 *** Когда вы получаете результат, осторожно и безопасно обработайте данные результата.
            // Опущено, поскольку это образец. Пожалуйста, обратитесь к разделу «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();
                }
            }
        } catch (SecurityException ex) {
            logLine(" Исключение:" + ex.getMessage());
        }
        finally {
            если (курсор != null) cursor.close();
        }
    }

    // В случае, если это приложение запрашивает временный доступ к поставщику контента,
    // и поставщик контента пассивно предоставляет этому приложению разрешение на временный доступ.
    public void onGrantRequestClick(View view) {
        Intent intent = new Intent();
        intent.setClassName(TARGET_PACKAGE, TARGET_ACTIVITY);
        try {
            startActivityForResult(intent, REQUEST_CODE);
        } catch (ActivityNotFoundException e) {
            logLine("Активность поставщика контента не найдена.");
        }
    }

    private boolean providerExists(Uri uri) {
        ProviderInfo pi = getPackageManager().resolveContentProvider(uri.getAuthority(), 0);
        return (pi != null);
    }

    private TextView mLogView;

    // Если поставщик контента активно предоставляет этому приложению временный доступ,
    // то это приложение активно запрашивает его.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mLogView = (TextView)findViewById(R.id.logview);
    }

    private void logLine(String line) {
        mLogView.append(line);
        mLogView.append("¥n");
    }
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-android-app-sec-guidebook.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-android-app-sec-guidebook.git
oschina-mirror
wizardforcel-android-app-sec-guidebook
wizardforcel-android-app-sec-guidebook
master