0

I am not able to publish my apk to Google playstore. Getting SQL Injection error. However I have fixed the SQLiteQueryBuilder setStrict problem as mentioned by Support. Not able to fix the ProjectionMap which is suggested. my projection array is generating values like this -

0 = "_id"
1 = "latitude"
2 = "longitude"
3 = "city"
4 = "last_update"
----------------
0 = "_id"
1 = "timezone_id"
2 = "city"
3 = "temperature"
4 = "condition_code"
5 = "weather_condition"
6 = "latitude"
7 = "longitude"
--------------
0 = "_id"
--------------
0 = "_id"
1 = "timezone_id"
2 = "city"
3 = "area"
4 = "time_diff"
5 = "temperature"
6 = "humidity"
7 = "wind_direction"
8 = "wind_speed"
9 = "weather_condition"
10 = "condition_code"
11 = "latitude"
12 = "longitude
--------------

Here is my complete code snippit and given below. My question is I am not using any SSLError handler.

package ch.corten.aha.worldclock.provider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.text.TextUtils;

import ch.corten.aha.worldclock.provider.WorldClock.Cities;
import ch.corten.aha.worldclock.provider.WorldClock.Clocks;

public class WorldClockContentProvider extends ContentProvider {

private WorldClockDatabase mClockDbHelper;
private CityDatabase mCityDbHelper;

private static final int CLOCKS = 1;
private static final int CLOCKS_ITEM = 2;
private static final int CITIES = 3;
private static final int CITIES_ITEM = 4;

private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static {
    URI_MATCHER.addURI(WorldClock.AUTHORITY, Clocks.TABLE_NAME, CLOCKS);
    URI_MATCHER.addURI(WorldClock.AUTHORITY, Clocks.TABLE_NAME + "/#", CLOCKS_ITEM);
    URI_MATCHER.addURI(WorldClock.AUTHORITY, Cities.TABLE_NAME, CITIES);
    URI_MATCHER.addURI(WorldClock.AUTHORITY, Cities.TABLE_NAME + "/#", CITIES_ITEM);
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    switch (URI_MATCHER.match(uri)) {
    case CLOCKS:
        break;
    case CLOCKS_ITEM:
        selection = "_ID = " + uri.getLastPathSegment();
        break;
    case CITIES:
    case CITIES_ITEM:
        throw citiesReadOnly();
    default:
        throw invalidUri(uri);
    }

    SQLiteDatabase db = getClockDbHelper().getWritableDatabase();
    int deleted = db.delete(Clocks.TABLE_NAME, selection, selectionArgs);
    if (deleted > 0) {
        getContext().getContentResolver().notifyChange(uri, null);
    }
    return deleted;
}

@Override
public String getType(Uri uri) {
    switch (URI_MATCHER.match(uri)) {
    case CLOCKS:
        return Clocks.CONTENT_TYPE;
    case CLOCKS_ITEM:
        return Clocks.CONTENT_ITEM_TYPE;
    case CITIES:
        return Cities.CONTENT_TYPE;
    case CITIES_ITEM:
        return Cities.CONTENT_ITEM_TYPE;
    default:
        throw invalidUri(uri);
    }
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    switch (URI_MATCHER.match(uri)) {
    case CLOCKS:
        break;
    case CITIES:
        throw citiesReadOnly();
    default:
        throw invalidUri(uri);
    }

    SQLiteDatabase db = getClockDbHelper().getWritableDatabase();
    long id = db.insert(Clocks.TABLE_NAME, null, values);
    Uri insertUri = ContentUris.withAppendedId(uri, id);
    getContext().getContentResolver().notifyChange(insertUri, null);
    return insertUri;
}

private static IllegalArgumentException invalidUri(Uri uri) {
    return new IllegalArgumentException("URI not recognized: " + uri.toString());
}

private static IllegalArgumentException citiesReadOnly() {
    return new IllegalArgumentException("Cannot write cities, they are read-only.");
}

@Override
public boolean onCreate() {
    return true;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    String table;
    SQLiteOpenHelper helper;
    int match = URI_MATCHER.match(uri);
    switch (match) {
    case CLOCKS:
    case CLOCKS_ITEM:
        table = Clocks.TABLE_NAME;
        helper = getClockDbHelper();
        break;
    case CITIES:
    case CITIES_ITEM:
        table = Cities.TABLE_NAME;
        helper = getCityDbHelper();
        break;
    default:
        throw invalidUri(uri);
    }

    switch (match) {
    case CLOCKS:
    case CITIES:
        if (TextUtils.isEmpty(sortOrder)) {
            sortOrder = "_ID ASC";
        }
        break;
    case CITIES_ITEM:
    case CLOCKS_ITEM:
        selection = "_ID = " + uri.getLastPathSegment();
        break;
    default:
        throw invalidUri(uri);
    }

    SQLiteDatabase db = helper.getReadableDatabase();
   SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    qb.setTables(table);
    qb.setStrict(true);
    HashMap<String, String> projectionMap = new HashMap<String, String>();


    Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
    c.setNotificationUri(getContext().getContentResolver(), uri);
    return c;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
    switch (URI_MATCHER.match(uri)) {
    case CLOCKS:
        break;
    case CLOCKS_ITEM:
        selection = "_ID = " + uri.getLastPathSegment();
        break;
    case CITIES:
    case CITIES_ITEM:
        throw citiesReadOnly();
    default:
        throw invalidUri(uri);
    }

    SQLiteDatabase db = getClockDbHelper().getReadableDatabase();
    int updated = db.update(Clocks.TABLE_NAME, values, selection, selectionArgs);
    if (updated > 0) {
        getContext().getContentResolver().notifyChange(uri, null);
    }
    return updated;
}

private WorldClockDatabase getClockDbHelper() {
    if (mClockDbHelper == null) {
        mClockDbHelper = new WorldClockDatabase(getContext());
    }
    return mClockDbHelper;
}

private CityDatabase getCityDbHelper() {
    if (mCityDbHelper == null) {
        mCityDbHelper = new CityDatabase(getContext());
    }
    return mCityDbHelper;
}

}

Updated Code

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    qb.setTables(table);
    qb.setStrict(true);
    HashMap<String, String> projectionMap = new HashMap<String, String>();


    Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);

Not sure how will update the hashmap

Biswajit Das
  • 594
  • 6
  • 22
  • 3
    First off, post your code, do not link to it. Secondly, they tell you where the problem is. If you aren't using it, some library is. – Gabe Sechan Sep 21 '18 at 01:18
  • @GabeSechan please have a code. Yes I am not using any library. – Biswajit Das Sep 21 '18 at 01:34
  • 3
    Are they complaining about a SQL injection problem, or a SSL problem? I definitely see a SQL injection problem- you're passing through the selection in query, which can be called by an outside app, directly through to your db. That's asking for SQL injection. You also aren't properly using the selectionArgs and bound query parameters in the CLOCKS_ITEM and CITIES_ITEM cases opening up another SQL injection path – Gabe Sechan Sep 21 '18 at 01:37
  • 1
    Avoiding SQL injections is simple: Never ever include a user parameter into an SQL string via String concat (´String + parameter`). User `PreparedStatement` instead for defining a parameter. – Robert Sep 22 '18 at 11:18
  • @Robert I have updated the code with the current schenerio. a pseudocode will help me. I have spent almost 4 day's on this. Weak developer here. – Biswajit Das Sep 22 '18 at 11:33
  • And what about `"_ID = " + uri.getLastPathSegment();` It is a string concat it is used by a delete command. – Robert Sep 22 '18 at 11:42
  • @Robert Thanks. so it should be replaced with ? Can you please update the code if possible. Thanks. – Biswajit Das Sep 22 '18 at 11:45
  • Start using the info I gave in my first comment and you end up here: [How do I use prepared statements in SQlite in Android?](https://stackoverflow.com/questions/433392) – Robert Sep 22 '18 at 11:46
  • @Robert thanks. But just to simplify exact problem with the below statements in the above code - **selection = "_ID = " + uri.getLastPathSegment();** for both section (query and delete method). How can I replace it as it needs to populate like **uri:content://ch.corten.aha.worldclock.provider/clocksvalues:area=Afghanistan order_key=4 city=Kabul latitude=34.52813 timezone_id=Asia/Kabul time_diff=270 longitude=69.17233** and sometimes **selection:last_update < 1537616063479** etc so its not static. – Biswajit Das Sep 22 '18 at 11:57
  • The statement in https://stackoverflow.com/a/436162/150978 is not static too. read it and learn from it. Note the `bindString` – Robert Sep 22 '18 at 12:00

0 Answers0