Устранение уязвимости SQL-инъекций на поставщике контента Android - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть разные приложения, которые делятся некоторыми данными друг с другом, это делается через контент-провайдера, но когда я загрузил apk, я получил электронное письмо, в котором говорилось: «Ваши приложения используют провайдера контента, который содержит уязвимость SQL-инъекции».

Существует несколько способов исправить это в соответствии с руководством Google:

Если уязвимый ContentProvider должен быть доступен другим приложениям:

  • Вы можете предотвратить SQL-инъекцию в SQLiteDatabase.query, используя строгий режим с картой проекции.Строгий режим защищает от вредоносных предложений выбора, а проекционная карта защищает от вредоносных предложений проекции.Вы должны использовать обе эти функции, чтобы убедиться, что ваши запросы безопасны.

  • Вы можете предотвратить внедрение SQL в SQLiteDatabase.update и SQLiteDatabase.delete, используя предложение выбора, которое использует «?»в качестве заменяемого параметра и отдельного массива аргументов выбора.Ваше предложение выбора не должно быть построено из ненадежных входных данных.

Но мне не ясно, как поступить с любым из решений, я не понимаю, как именно использовать карту проекцииили измените код, используя предложение выбора, которое использует «?».Я имею в виду, я видел несколько примеров про ProjectionMap, но какой ключ / значение ему нужен для запроса?Нужно ли писать явные значения, которые я хочу?но что, если это универсальный метод, и я не знаю в этой части кода, что я хочу получить?Или как мне преобразовать любой запрос в ProjectionMap?

Надеюсь, я объясню себе это.

Вот мой код:

     @Override
public boolean onCreate() {
    gOpenHelper = new GameDBHelper(getContext());
    return true;
}

/**
 * Builds a UriMatcher that is used to determine witch database request is being made.
 */
public static UriMatcher buildUriMatcher(){
    String content = GamesContract.CONTENT_AUTHORITY;

    // All paths to the UriMatcher have a corresponding code to return
    // when a match is found (the ints above).
    UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    matcher.addURI(content, GamesContract.PATH_GAME, GAME);
    matcher.addURI(content, GamesContract.PATH_GAME + "/#", GAME_ID);

    return matcher;
}

@Override
public String getType(Uri uri) {

    switch(sUriMatcher.match(uri))
    {
        case GAME:
            return GameEntry.CONTENT_TYPE;
        case GAME_ID:
            return GameEntry.CONTENT_ITEM_TYPE;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    final SQLiteDatabase db = gOpenHelper.getWritableDatabase();
    Cursor retCursor;
    switch(sUriMatcher.match(uri))
    {
        case GAME:
            retCursor = db.query(
                    GameEntry.TABLE_NAME,
                    projection,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    sortOrder
            );
            break;
        case GAME_ID:
            long _id = ContentUris.parseId(uri);

            retCursor = db.query(
                    GameEntry.TABLE_NAME,
                    projection,
                    GameEntry._ID + " = ?",
                    new String[]{String.valueOf(_id)},
                    null,
                    null,
                    sortOrder
            );
            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }
    retCursor.setNotificationUri(getContext().getContentResolver(), uri);
    return retCursor;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    final SQLiteDatabase db = gOpenHelper.getWritableDatabase();
    long _id;
    Uri returnUri;

    switch(sUriMatcher.match(uri))
    {
        case GAME:
            _id = db.insert(GameEntry.TABLE_NAME, null, values);

            if(_id > 0){
                returnUri = GameEntry.BuildGameUri(_id);
            } else{
                throw new UnsupportedOperationException("Unable to insert rows into: " + uri);
            }
            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    getContext().getContentResolver().notifyChange(uri, null);
    return returnUri;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    final SQLiteDatabase db = gOpenHelper.getWritableDatabase();
    int rows; // Number of rows effected

    switch(sUriMatcher.match(uri))
    {
        case GAME:
            rows = db.delete(GameEntry.TABLE_NAME, selection, selectionArgs);
            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    // Because null could delete all rows:
    if(selection == null || rows != 0){
        getContext().getContentResolver().notifyChange(uri, null);
    }

    return rows;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    final SQLiteDatabase db = gOpenHelper.getWritableDatabase();
    int rows;

    switch(sUriMatcher.match(uri))
    {
        case GAME:
            rows = db.update(GameEntry.TABLE_NAME, values, selection, selectionArgs);
            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    if(rows != 0){
        getContext().getContentResolver().notifyChange(uri, null);
    }

    return rows;
}

}

1 Ответ

0 голосов
/ 29 мая 2019

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

Проблема связана сзапросы, которые требуют предложения 'where';в моем случае обновляй и удаляй, чтобы исправить это, мне нужно было не использовать параметр выбора как есть, мне нужно было сделать что-то вроде:

GamesContract.Games.GAME_NAME + " = ?"

db.delete(GamesContract.Games.TABLE_NAME, GamesContract.Games.GAME_NAME + " = ?", selectionArgs);

В основном название таблицы + "=?"selection.

Таким образом, вы заставляете обновлять только нужную таблицу и не позволяете SQL-инъекции изменять любое место в вашей базе данных тем же способом.

...