38

My key is restricted using package name and SHA1, still Google Play store shows this warning.

Any idea why it is showing like this. I defined my API key in build.gradle file and using it from there.

Smeet
  • 3,787
  • 1
  • 32
  • 44
  • You should not define your API key directly in build.gradle file – GOVIND DIXIT Jul 05 '19 at 04:52
  • i am getting same warning.. any Solution ? – JohnRaja Aug 30 '19 at 10:13
  • did you find a solution for it ? – M.SH Jun 08 '20 at 10:54
  • Nope. I did not find any satisfactory answer from anywhere. – Smeet Jun 16 '20 at 09:37
  • 1
    I think the proper solution is get the key from API, and use it in on fly. If we do this way periodically we can the change the key. – user2851150 Sep 24 '20 at 08:21
  • I have restricted the api using package name in google api console. and I have tried even spliting the api key into four parts and containating . still the google pre launch report throwing error. pls help me – Grace Venkat Nov 04 '21 at 15:29
  • @GraceVenkat did you manage to solve the problem? I am in the same situation now. Even when I put API restrictions on the key, I am still getting the same error. I am convinced that even the official docs https://developers.google.com/maps/documentation/android-sdk/config#step_2_add_your_api_key_to_the_project won`t solve the problem. – Patrik Onderka Mar 21 '22 at 19:07

9 Answers9

15

As per google's recommendation putting restrictions such as specifying the package name and also the SHA-1 key is the way to go.

It has been explained here: https://cloud.google.com/docs/authentication/api-keys#securing_an_api_key

Now, the problem here is that whatever you do your API key will end up in the codebase i.e if you specify it outside your codebase (via some properties file) but pass it in via the BuildConfig field during the build phase (the whole key is visible to someone decompiling your code as it is now part of BuildConfig class file) or you split it up and concatenate in the codebase (the split keys are still visible and anyone can concatenate them by seeing the usage to get the final key from a decompiled apk).

The split key version will get rid of the warning in the Play Console, but the key is still exposed.

My suggested solution thus would be to encode your API key and pass that around your codebase. Just before using it you decode it back.

A very simple example can be:

Please use a better encoding algo and not this, this is for demonstration purpose only. Here we are using Base64 encoding.

import android.util.Base64

fun main() {
   // API Key = "123456ABC"
   val myEncodedApiKey = "MTIzNDU2QUJD" // Should be passed via BuildConfig
   val decodedApiKey = Base64.decode(myEncodedApiKey, Base64.DEFAULT)

   // Now use `decodedApiKey` in your codebase.
   val decodedApiKeyString = String(decodedApiKey)
}

Why is this better?

  1. Your key is not exactly the same as in your GCP project.
  2. The play console when it scans your codebase, cannot match it back to your GCP project API keys. Thus no warnings.

Update (clarification on using the google-services.json file for API key):

The solution to use the API key from google-services.json isn't quite valid. google-services.json is generated file usually if you connect your firebase account. The API key defined there has a different restriction model. The one you define in your GCP project is different, allowing you to pass in package name and an SHA-1 key as well as restricted to a specific kind of API access such as Youtube only access. So if one was to use the API keys from google-services.json then you are essentially not using the restrictions you set up in your GCP account. GCP accounts do not generate google-services.json file.

To bring into perspective here is an official doc from Google for setting up Youtube API which uses GCP project defined API keys and in the docs, it mentions to directly put the keys in the code. (which is anyways wrong as it is exposed, but that's Google for you).

https://developers.google.com/youtube/android/player/setup

Nowhere in any docs, it is referred to use google-services.json file for retrieving API keys.

Nishant Srivastava
  • 4,625
  • 2
  • 23
  • 34
  • this is wrong according to google guidelines your api key should not present anywhere in your source tree . in your answer its still there in your source code in encrypted format. anyone can easily do decrypt that key using base64 converter. – Sahil Arora Jul 22 '19 at 10:22
  • 3
    I already explained but this is way better than what you have suggested in 2 answers, which expose in entirety the API key as part of a string resource, or the split version, so that means it is already part of the source code. If you were to encode it with a private key, this makes your key way more secure than it will be using any other approach. – Nishant Srivastava Jul 22 '19 at 10:28
  • yea i.e i posted another answer to get Api key from google-service.json file as google guidelines it's not in source tree . There is a API KEY in google-service.json file , that api key you will get it in google developer console so you can easily restrict it to app level or api level – Sahil Arora Jul 22 '19 at 10:31
  • 2
    Here whatever the keys are there in google-service json, it will be added into string file, when app building time. So ultimately the key will be there in the code base. – user2851150 Sep 24 '20 at 08:17
6

Got Google Play Ads? It would appear that, at least as of 8-1-19, an api key that triggers this is embedded within the full google play services ads library. That is--

implementation 'com.google.android.gms:play-services-ads:18.1.1'

triggers the alert, but

implementation 'com.google.android.gms:play-services-ads-lite:18.1.1'

which removes some code that already exists in the play store, does not. The error itself cites an obfuscated method, which I tracked down in the apk to:

com/google/android/gms/internal/ads/[obfuscatedstring]/<clinit>()

This appears to set a bunch of constants. One of which is called gads:safe_browsing:api_key

Just in case I'm wrong and this isn't in everyone's code I won't reproduce it here, but it sure looks to me like a GCP key that might trigger the issue. It is 40 characters and this identical key can be found elsewhere on the Internet.

My guess is, if you're using the play-services-ads library (as opposed to the Firebase library), it is probably seeing this string and sounding an alarm.

fattire
  • 5,083
  • 2
  • 21
  • 33
  • 1
    I see exactly the same problem in Google Play console but I'm totally confused. It seems to be bug in Google's code. Right? – Tomáš Hubálek Aug 03 '19 at 07:18
  • 1
    That's my guess. I think the key in the play-services-ads library is triggering the (false) alarm. If it's not a false alarm and they didn't mean to put that API key in the library, they should probably remove it then :) – fattire Aug 03 '19 at 16:47
4

You can remove this warning by split your keys into 4 parts like this

public static final String API_KEY_PART_1 = "Asdsdfdd-";

public static final String API_KEY_PART_2 = "dfsFdsdsFdd";

public static final String API_KEY_PART_3 = "Pgdhs_SfSfs";

public static final String API_KEY_PART_4 = "fdfDDSD";

and use it by concatenate Strings

.attest(nonce.getBytes(), Constants.API_KEY_PART_1+Constants.API_KEY_PART_2+Constants.API_KEY_PART_3+Constants.API_KEY_PART_4)

NOTE: Make sure you restrict your API key to Applications Access only. otherwise if someone decompile your apk and use your api key then it may be increase your billing.

Restric your API's Key with SHA & Package name click here for details

Sahil Arora
  • 435
  • 1
  • 3
  • 11
  • that is correct. I already restricted the key with package and SHA1. Then also why google is giving warning ? Because once I restrict, is there any chances of being misuse the key ? – Smeet Jul 10 '19 at 11:52
  • yes, no one can misuse this key if you restrict it.This warning is still showing because while you upload apk and google automation Testing check this key is present in code they throw an exposed key warning so now you can split this keys to ignore this warning from play store – Sahil Arora Jul 11 '19 at 05:26
  • i tired this approach and so far I don’t see the play store warning on the new version – Sahil Arora Jul 11 '19 at 07:09
  • 1
    I tried this approach, but still showing the warning message. – Amit Feb 14 '20 at 11:38
  • is there any particular reason as why it is split into 4? – NaDie Mar 04 '20 at 14:26
  • I have restricted the key usage to app, Still google throwing the error, If I split or encode the key will the problem resolve ? – user2851150 Sep 24 '20 at 08:20
3

Sorry, a bit late to the game here...

Follow the below steps:

  1. The Firebase console will help you download the google-services.json. In addition, the Quickstart guides for most APIs have instructions for generating this file. Once you have downloaded the google-services.json file,copy it into the app/ folder of your Android Studio project, or into the app/src/{build_type} folder if you are using multiple build types.
  2. The Google Cloud Console will help you to enable the GCP(ex: Places API,Map SDK for android etc.) in API Library section by choosing the project which was created in the Firebase console.
  3. you could get the api key with:

    activity.getResources().getString(R.string.google_api_key);

String key name is "google_api_key" for getting the API Key.

FYI, The google-services.json file gets parsed and its values get added to an xml (path: app/build/generated/res/google-services/{build_type}/values/values.xml) which you have access to: https://developers.google.com/android/guides/google-services-plugin

vikas
  • 129
  • 1
  • 8
2

Sorry, a bit late as my previous answer was just bypass the warning after some research i found an appropriate fix for this problem

you can get api key from google json file. The google-services.json file gets parsed and its values get added to an xml which you have access to all the elements of json as Android resources in your Java code click here for details

Below is an example to access the google api key from json file :

activity.getResources().getString(R.string.google_api_key);

Sahil Arora
  • 435
  • 1
  • 3
  • 11
  • How is this valid? The google_api_key is a different key than the one defined in the GCP project and that also restricts to a specific app package and SHA-1 key. – Nishant Srivastava Jul 22 '19 at 09:33
  • Why it is different ? You should use same key and remove unnecessary keys from Google cloud console . @Nishant. – Sahil Arora Jul 22 '19 at 09:35
  • Because google_api_key that comes from google-services.json is provided by firebase project. The api key defined in the GCP project doesn't generate the google-services.json. So if one uses the google_api_key from google-services.json file, they are using an API key which has no restrictions setup. – Nishant Srivastava Jul 22 '19 at 09:41
  • it should be there in your developer console. please check your google console. In your console you can restrict that key with package name & SHA-1 . – Sahil Arora Jul 22 '19 at 09:45
  • These are two things you are mentioning. First of all, google play console doesn't provide a google-services.json. Second, we are talking about GCP project here, so you goto Googe Cloud console. Now about the API restrictions, that is possible to be setup only in the API section of GCP console. This has been explained well here: https://cloud.google.com/docs/authentication/api-keys#securing_an_api_key – Nishant Srivastava Jul 22 '19 at 09:49
  • There is no mention of google-services.json anywhere. This leads me to believe that even though this works, this is actually not secure. Because the API key from google-service.json has no restrictions setup. – Nishant Srivastava Jul 22 '19 at 09:51
  • You are not getting my point . I am saying the **KEY** in google.service.json file should be there in console. not the google-service.json file. you can restrict that key, which were in the json file. – Sahil Arora Jul 22 '19 at 09:55
  • google.service.json is auto-generated file. You don't copy-paste its contents to your GCP project. Please read my answer below. – Nishant Srivastava Jul 22 '19 at 10:13
  • i know we can't copy paste its content to your GCP project. i think you don't know about google-service.json file. This auto generated .json file used a GCP API KEY with name "current_key" . open your json file and see this key. `"api_key": [ { "current_key": "AIzaSyD36SADr33OVFDSAFSFASa43fdfasdf" } ],` the same API Key is auto generated in your google developer console and restrict that auto genreted api key. See here about google-service.json file https://developers.google.com/android/guides/google-services-plugin – Sahil Arora Jul 22 '19 at 10:17
  • Please refer to the link you shared itself. The docs explicitly mention this is autogenerated and is for google apis or firebase projects. Not for GCP apis. – Nishant Srivastava Jul 22 '19 at 10:29
1

it may be late, but will help some of the guys,

There is no link between Firebase JSON configuration file and google maps integration API key

Firebase Clarification

If you integrate Firebase in your app, it requires the JSON configuration to be placed in your code, and this is the only way to connect the app with Firebase.

but in Google maps, it is totally different. It will provide the key - to place in our code but not hard-coded or as it is,

Solution:

I have combined both solutions to work around, from Nishant and Sahil Arora, to encode the key into something else and split it into pieces to make it somehow difficult to decode back, I am splitting into the four-part, you can as much as you feel good:

Decode your ApiKey

// getEncodedApiKey result encoded key,
// splitted into four the part
String thePartOne = "encodedPartOneMaybe";
String thePartTwo = "encodedPartNextMaybe";
String thePartThree = "encodedPartNextMaybe";
String thePartFour = "encodedPartLast";

public String getSplitedDecodedApiKey(){

    return new String(
            Base64.decode(
                    Base64.decode(
                                thePartOne +
                                    thePartTwo +
                                    thePartThree +
                                    thePartFour ,
                            Base64.DEFAULT),
                    Base64.DEFAULT));
}

Encode your ApiKey

//just to encode the string before splitting it into the pieces
//and remove this method from the source code
public void getEncodedApiKey(){

    String plainApiKey = "xiosdflsghdfkj"; //
    String encodedApiKey = new String(
            Base64.encode(
                    Base64.encode(plainApiKey.getBytes(),
                            Base64.DEFAULT),
                    Base64.DEFAULT));
    Log.i(TAG, "getEncodedApiKey: " + encodedApiKey);
}
Ramesh R
  • 6,683
  • 3
  • 22
  • 34
Ali Tamoor
  • 796
  • 11
  • 16
1

better to use firbase firestore database to store your api key and access it. Firestore is safe and highly secure as its a product of Google.

enter image description here

and access it using this code

mDatabase.collection(COLLECTION_NAME)
.document("DOCUMENT_NAME")
.get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
Log.d(TAG, "google_places_api_key: " + documentSnapshot.get("google_places_api_key") + "");
}
});

This method is safe and secure and your api key will not access by any Man in the middle attack and of course play store will allow this method.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 10 '21 at 10:33
0

Had the same issue for a long time, in my case while initializing the Youtube Player with google api key.

It didn't go away even after restricting the API Key with SHA & Package name.

However, after migrating to androidX the Security alert is gone in Google Play Console.

Abhisek Mallick
  • 116
  • 2
  • 5
0

This error comes when developers write the API keys exposed as hardcoded strings in Java or XML files. Use it inside a strings.xml. And reference it as mentioned below. It will get resolved automatically.

geoApiContext = new GeoApiContext.Builder()
                    .apiKey(getResources().getString(R.string.maps_api_key))
                    .build();
Shadab K
  • 1,599
  • 13
  • 25