Your app contains exposed Google Cloud Platform (GCP) API keys. Please see this Google Help Center article for details.
Vulnerable locations:
com.abc.Youtube_Player->onCreate
This is How my code look at the back end
public class Youtube_Player extends AppCompatActivity implements YouTubePlayer.OnInitializedListener {
// YouTube player view
public static final String GOOGLE_API_KEY = "<api key>";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_youtube__player);
// Initializing video player with developer key
mPlayerView.initialize(GOOGLE_API_KEY, this);
}
}
You have API Key in the code.
As a best practice, you should keep the secret keys in a secure system like Google Secret Manager, HashiCorp Vault, encrypted secure GCS Bucket etc.. If these option are not feasible for you, still try to put secret keys in some other property file and control access of that file.
To avoid this warning message from the console:
Leaked GCP API Keys Your app contains exposed Google Cloud Platform
(GCP) API keys. Please see this Google Help Center article for
details.
You must define the values you want to "hide" inside your gradle.properties file (if it doesn't exist, you can create it)
JORGESYS_API_KEY=key=AI9876IoaNutaEFrumoAsaAsa123An8mTRk-U
SECRET_CLIENT_API_KEY=key=AIzaSyJorgeSysIsCoOlaeB12GSET-U
SECRET_TOKEN_API_KEY=key=AIzaS12JorgeSysIsCoOlsauPrOsTaeB12GSET-U
and define the reference of these values inside app/build.gradle
android {
...
...
defaultConfig {
...
...
...
//*Defined in gradle.properties
buildConfigField "String", "JORGESYS_API_KEY", "\"$JORGESYS_API_KEY\""
buildConfigField "String", "SECRET_CLIENT_API_KEY", "\"$SECRET_CLIENT_API_KEY\""
buildConfigField "String", "SECRET_TOKEN_API_KEY", "\"$SECRET_TOKEN_API_KEY\""
}
}
When generating your project, the BuildConfig class will be generated that will contain the values and that you can assign to your application when compiling.
val myAPIKEY = BuildConfig.JORGESYS_API_KEY
These values cannot be obtained by "reverse engineering"! :-)
You have define your api key with 'public static' it means your api key access any where in the app.And chance to leak your api key.You need to change from 'public static' to private.
Complete guide for use API Keys and avoid Leaked GCP API Keys security issue in Google Play Console : https://stackoverflow.com/a/71155071/13387867
Related
I am building an Android App which communicates with my REST API that is protected by Spring Security.
Since the Android App is "public" and no keys etc is secure I want to create diffrent obstacles and make things complicated to protect my API as much as possible.
One way in which I would like to add more security is to make sure that the one calling my API has a certificate. I don't want to create thousands of certificates in my APIs trust-store so I just want to make sure that the caller have one single certificate that I hid away in a keystore in my Android app.
In the examples I have found it seems like a "normal" X509Certificate authentication in Spring Security requires a unique certificate for every user and then this certificate replaces Basic auth or JWT auth. I would like to have individual client JWT tokens but make sure that every call brings my ONE Android App certificate to make (more) sure that someone is calling my API from my Android app.
Is this possible or is it just not what it is for?
When you create a RestTemplate you can configure it with a keystore and trust-store so in that end it should be easy. But as for protecting my REST API it seems more difficult since I want both certificate + JWT token or Basic auth.
I am not using XML configuration for my securityconfig. I instead extend WebSecurityConfigurerAdapter. It would be great if this was configurable in the configure(HttpSecurity http) method, but I'm thinking that maybe I could achieve this in a OncePerRequestFilter somehow? Perhaps configure a filter before my JwtAuthFilter?
Edit:
In all the examples I have found for configuration of spring security they always seems to use the certificate as an authentication. I just want to configure so that when someone call example.com/api/** it checks so that the certificate is approved by my custom trust store (so that I "know" it is probably a call from my app) but if someone call example.com/website it should use the default java trust store.
If someone call example.com/api/** I would like my server to
check certificate and kill the connection if the certificate is not approved in my custom truststore.
If certificate is ok, establish https (or move on if I can't kill the connection before it have already established https-connection) to user auth with Basic-/JWT-authentication.
I think I figured it out. Here is how I configured it and it seems to work.
The "/**" endpoint is the website which should work with any browser without any specific certificate, but it requires Admin authority (you need to login as admin).
The "/api/**" and "/connect/**" endpoints require the correct certificate, the correct API-key and valid Basic- or JWT-token authentification.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/loginForm")
.loginProcessingUrl("/authenticateTheUser")
.permitAll()
.and()
.logout()
.permitAll().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
http.requestMatchers()
.antMatchers("/connect/**","/api/**")
.and()
.addFilterBefore(new APIKeyFilter(null), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtAuthorizationFilter(), BasicAuthenticationFilter.class)
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/connect/**").hasAnyRole("MASTER,APPCALLER,NEGOTIATOR,MEMBER")
.antMatchers("/api/**").hasAnyRole("MASTER,MEMBER,ANONYMOUS");
}
The ApiKeyFilter class is the one that check the api-key and also make sure that the certificate used in the call is approved in my server trust-store. The api-key check is all that I had to configure, the extended X509AuthenticationFilter will automatically check the request certificate. My ApiKeyFilter looks like this:
public class APIKeyFilter extends X509AuthenticationFilter {
private String principalRequestHeader = "x-api-key";
private String apiKey = "XXXX";
public APIKeyFilter(String principalRequestHeader) {
if (principalRequestHeader != null) {
this.principalRequestHeader = principalRequestHeader;
}
setAuthenticationManager(new AuthenticationManager() {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if(authentication.getPrincipal() == null) {
throw new BadCredentialsException("Access Denied.");
}
String rApiKey = (String) authentication.getPrincipal();
if (authentication.getPrincipal() != null && apiKey.equals(rApiKey)) {
return authentication;
} else {
throw new BadCredentialsException("Access Denied.");
}
}
});
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return request.getHeader(principalRequestHeader);
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
X509Certificate[] certificates = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
if (certificates != null && certificates.length > 0) {
return certificates[0].getSubjectDN();
}
return super.getPreAuthenticatedCredentials(request);
}
}
Cred goes to these resources that helped me put things together:
Spring Boot - require api key AND x509, but not for all endpoints
spring security http antMatcher with multiple paths
I'm just trying to get a basic example of the Android Key Store system to generate a symmetric key. I followed the example in the tutorial (using Kotlin) but I get an error like so:
java.security.NoSuchProviderException: no such provider: AndroidKeyStore
Below is my code where the compiler is throwing an error:
val kpg: KeyGenerator = KeyGenerator.getInstance("DES", "AndroidKeyStore")
On my Gradle, I am using compileSdkVersion and targetSdkVersion to 28. I'm also have a minSdkVersion of 25. All of which should satisfy the Android's doc on using the AndroidKeyStore (min API level 18).
If I remove the provider, everything works like planned, since I'm assuming it goes to the default provider. The same goes for the KeyPairGenerator and KeyStore classes when I try the AndroidKeyStore provider.
Am I using the wrong provider keyword? Or is there some additional setup that I'm supposed to be doing?
Thanks,
Update 1 - So I kept searching and found that you can get a list of available providers on my system. Here's my code below:
for (p in Security.getProviders()) {
//Log.d(TAG, String.format("== %s ==", p.getName()))
println(String.format("== %s ==", p.getName()))
println(String.format("%s", p.info))
// for (s in p.getServices()) {
// //Log.d(TAG, String.format("- %s", s.getAlgorithm()))
// println(String.format("- %s", s.getAlgorithm()))
// }
}
Also, the results match what's in my $JAVA_HOME/jre/lib/security.java.security file:
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=apple.security.AppleProvider
So I guess my option is to add the AndroidKeyStore provider to this. I'll update this when I've tried that.
I found out that there's a bug at the moment with using the AndroidKeyStore with unit tests, which I didn't mention in my original question.
See here:
https://github.com/robolectric/robolectric/issues/1518
When doing a Geocoderequest in the Here API for Android I get the result FORBIDDEN for any search string.
Here is a snippet of the code (Kotlin) :
class GeoListner : ResultListener <MutableList<Location>>
{
override fun onCompleted(p0: MutableList<Location>?, p1: ErrorCode?) {
Log.d(this.javaClass.toString(),"Result code of search is ${p1?.name}")
}
}
fab_search.setOnClickListener { View ->
var currentPos = GeoCoordinate(49.2849,-123.1252)
val listner : ResultListener<MutableList<Location>> = GeoListner()
val request = GeocodeRequest("Granville").setSearchArea(currentPos,5000)
if (request.execute(listner) != ErrorCode.NONE)
{
}
}
This search area and string is picked from the HERE-API documentation for Here. Also i notice that the GeocodeRequest is deprecated, but the result for GeocodeRequest2 is the same error.
Anyone ?
Regards
Trond
Summary: Please ensure that you set the APP_ID and APP_CODE in the manifest file correctly.
For the background: Developers using HERE SDK with their app are required to register for a set of HERE credentials and to specify these credentials (App_Id and App_Code) in their app's Android manifest XML file. Failure to do so results in blocked access to certain features and degradation in the quality of other services.
To obtain these credentials visit the developer portal at https://developer.here.com/plans and register for a license. Once your project is created, you can generate these credentials on your Project Details page. If you already have a plan, you can also retrieve these credentials from your Project Details page.
Note: Credentials are unique to your account and your application's package namespace. Avoid reusing credentials across multiple applications.
I'm trying to use the Google Cloud Translation API in my application but whenever I try to translate something it comes up with this missing valid API error.
I've done the quickstart steps and that didn't work.
I've tried the steps in the client library authentication and that hasn't worked either.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: herrsa1.bit.translator, PID: 16598
com.google.cloud.translate.TranslateException: The request is missing a valid API key.
at com.google.cloud.translate.spi.v2.HttpTranslateRpc.translate(HttpTranslateRpc.java:61)
.. 18 more
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [{
"domain" : "global",
"message" : "The request is missing a valid API key.",
"reason" : "forbidden"
}],
"message" : "The request is missing a valid API key.",
"status" : "PERMISSION_DENIED"
}
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
... 4 more
at com.google.cloud.translate.spi.v2.HttpTranslateRpc.translate(HttpTranslateRpc.java:130)
... 19 more
If you are using client library and you have already downloaded your service account json file, try doing this:
// Instantiates a client
const translate = new Translate({
projectId: 'your project id', //eg my-proj-0o0o0o0o'
keyFilename: 'path of your service acount json file' //eg my-proj-0fwewexyz.json
});
instead of this:
// Instantiates a client
const translate = new Translate({projectId});
This way you need only your the service acount json file and the specific API enabled
The error on API key means you didn't create or use the key properly. You need to do the following for the key to work:
Create a service account
Create a key for above service account
Download the key to a location, for example, a local path
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the key, refer to samples in Quickstart tutorial
I'd reccomend doing #1 & #2 in GCP Console, and handling #3 & #4 in Cloud Shell.
The key your using does not have the permission to use Translate APIs.
To fix this :
Go to Google Cloud Platform console
Chose your project from the drop down menu in the top bar
Go to API & Services > Library
Search for Cloud Translation API and click on it
Enable it
Go to API & Services > Credentials
Select the key you are using in your Android App
From the menu called Restrict key, choose Cloud Translation API
Save your edit
Now the APIs will work properly.
I also tried to execute this sample program.
I followed the same instruction. But when I executing I got same error(The request is missing a valid API key).
I changed a line in the sample program.
Instead of
Translate translate = TranslateOptions.getDefaultInstance().getService();
I added
Translate translate = TranslateOptions
.newBuilder()
.setCredentials(
ServiceAccountCredentials
.fromStream(new FileInputStream(
"YourCredentialFilePath.json")))
.build().getService();
Now it is working.
Sample code after fix.
// Imports the Google Cloud client library
import java.io.FileInputStream;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.translate.Translate;
import com.google.cloud.translate.Translate.TranslateOption;
import com.google.cloud.translate.TranslateOptions;
import com.google.cloud.translate.Translation;
public class QuickstartSample {
public static void main(String... args) throws Exception {
//Instantiates a client
//Removed next line
//Translate translate = TranslateOptions.getDefaultInstance().getService();
//Added this line
Translate translate = TranslateOptions
.newBuilder()
.setCredentials(
ServiceAccountCredentials
.fromStream(new FileInputStream(
"YourCredentialFilePath.json")))
.build().getService();
//The text to translate
String text = "Hello, world!";
//Translates some text into Russian
Translation translation =
translate.translate(
text,
TranslateOption.sourceLanguage("en"),
TranslateOption.targetLanguage("ru"));
System.out.printf("Text: %s%n", text);
System.out.printf("Translation: %s%n", translation.getTranslatedText());
}
}
I'm trying to create Parse apps on the fly and use the keys while building my Android application. The API works great except for one point, it does not return the Client Key.
{
"appName": "my new app",
"dashboardURL": "https://www.parse.com/apps/my-new-app--30",
"applicationId": "oQqMyipkIgxYFXRROYTZsREfTcXp770awB1yMVrs",
"javascriptKey": "XAPZ7DoZHQIhMC8vPqN1m79wRIQyIXv7tmVIHmRs",
"windowsKey": "ZsyfFr0WtaQx6tsCokNSmTvjd05QCbCbMLzpChvP",
"webhookKey": "LyXnWJ3tRH56gK19KC1fjTvoUbdSUZoXhyO6khoT",
"restKey": "dzpdzYNkts2xZxPDVe7qC298Z20oIXhLJAPuY2Dw",
"masterKey": "0M2uUDZdKa1KYC1VBrmDaGK3chBaUMw0c2M4XXw1",
"clientPushEnabled": true,
"clientClassCreationEnabled": true,
"requireRevocableSessions": true,
"revokeSessionOnPasswordChange": true
}
And I need the client key as mentioned in the Android API:
Parse.initialize(this, "YOUR_APP_ID", "YOUR_CLIENT_KEY");
I have tried toggling the flags in vain.
What should I do inorder to access the Client Key?
Edit:
I'm talking about the Client Key which appears here: http://postimg.org/image/f76lj6xcr/
This was a minor bug in the Parse REST API. They fixed it within 48 hours after reporting.