The SafetyNet service includes a reCAPTCHA API that you can use to protect your app from malicious traffic. In this tutorial we would see how we can implement Google SafetyNet RECAPTCHA in Android Studio.
ReCAPTCHA is a free service that protects your website from spam and abuse. ReCAPTCHA uses an advanced risk analysis engine and adaptive CAPTCHAs to keep automated software from engaging in abusive activities on your site. It does this while letting your valid users pass through with ease.
The reCAPTCHA Advantage
Advanced Security
State of the art spam & abuse protection for your website
Ease of Use
Low friction, effortless interaction for your users
Creation of Value
Apply the human bandwidth to benefit people everywhere
Steps to implement Google SafetyNet ReCAPTCHA in Android Studio
Getting reCAPTCHAKey Pair
Before using a Recaptcha service in your application you’ll need two key pairs. Go to the https://g.co/recaptcha/androidsignupto register a key pair for use with the SafetyNetreCAPTCHA API.
Project Setup :
1. Create a new project in an android studio from File->New Project-> and select the Basic Activity from layouts. While creating your project, make sure to use the package name you have registered on the reCAPTCHA dashboard.
2. We need to add SafetyNETAPI dependency to our build.gradle(module-level) file, as they are a part of Google play services. We are also using Volley dependency here to send an HTTP call to our server to validate the captcha token(user response token) on the server-side.
apply plugin: 'com.android.application' ... dependencies { compile 'com.google.android.gms:play-services-base:11.0.1' compile 'com.google.android.gms:play-services-basement:11.0.1' compile 'com.google.android.gms:play-services-safetynet:11.0.1' compile 'com.google.android.gms:play-services-tasks:11.0.1' }
3. We will need to add Internet permissions in the Manifest file.
<uses-permissionandroid:name="android.permission.INTERNET"/>
4. Add the below code in a string.xml file of your project resources folder.
<string name="btnClick">Confirm not a robot</string> <string name="confirmation">Confirmed you are not a robot</string>
5. We will edit Layout file activity_main.xml from res/layout ,by opening it from ->layout XML File.
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btnClick" tools:ignore="MissingConstraints"/> </android.support.constraint.ConstraintLayout> main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:paddingLeft="15dp" android:text="@string/confirmation" android:textSize="25sp" android:textStyle="bold"/> </LinearLayout>
6. Create a new class named Services.java
public class Services extends Application { public static final String TAG = Services.class .getSimpleName(); private RequestQueuemRequestQueue; private static Services mInstance; @Override public void onCreate() { super.onCreate(); mInstance= this; } public static synchronized Services getInstance(MainActivitymainActivity) { return mInstance; } public RequestQueuegetRequestQueue() { if (mRequestQueue== null) { mRequestQueue= Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } public <T>void addToRequestQueue(Request<T>req, String tag) { req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } public <T>void addToRequestQueue(Request<T>req) { req.setTag(TAG); getRequestQueue().add(req); } public void cancelPendingRequests(Object tag) { if (mRequestQueue!= null) { mRequestQueue.cancelAll(tag); } } }
7. Edit in MainActivity.java
public class MainActivityextends AppCompatActivity { String user_response_token; private static final String TAG = MainActivity.class.getSimpleName(); // TODO - replace the SITE KEY with yours private static final String SAFETY_NET_API_SITE_KEY = "6Ld8j1cUAAAAAO6nHV4p6-Yf9Q_Tc5tZw5_yfDfM"; // TODO - replace the SERVER URL with yours private static final String URL_VERIFY_ON_SERVER = "https://www.google.com/recaptcha/api/siteverify "; // TODO - replace the SECRET KEY with yours private static final String SAFETY_NET_API_SECRET_KEY = "6Ld8j1cUAAAAAK_PEFKFYtXg00--rBtkQGz3YKFC "; Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { validateCaptcha(); } }); } private void validateCaptcha() { { // Showing reCAPTCHA dialog SafetyNet.getClient(this).verifyWithRecaptcha(SAFETY_NET_API_SITE_KEY) .addOnSuccessListener(this, new OnSuccessListener<SafetyNetApi.RecaptchaTokenResponse>() { @Override public void onSuccess(SafetyNetApi.RecaptchaTokenResponse response) { Log.d(TAG, "onSuccess"); //user_response_token is a variable which carries the user's input user_response_token=response.getTokenResult(); if (!user_response_token.isEmpty()) { // check if the user input is not empty Log.e("received","received"); // Received captcha token from user // This token will further send to the server for validation using the SECRET key tokenVerificationOnServer(user_response_token); } } }) .addOnFailureListener(this, new OnFailureListener() { @Override public void onFailure(@NonNullException e) { if (e instanceofApiException) { ApiExceptionapiException = (ApiException) e; Log.d(TAG, "Error message: " + CommonStatusCodes.getStatusCodeString(apiException.getStatusCode())); } else { Log.d(TAG, "Unknown type of error: " + e.getMessage()); } } }); } } private void tokenVerificationOnServer(String user_response_token) { StringRequeststrReq = new StringRequest(Request.Method.POST, URL_VERIFY_ON_SERVER, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d(TAG, response.toString()); try { JSONObjectjsonObject = new JSONObject(response); booleansuccess = jsonObject.getBoolean("success"); if (success) { Log.e("server no error","server no error"); // Congratulations! captcha verified successfully on server //move to next screen using intents Intent i=new Intent(MainActivity.this,Next_Activity.class); startActivity(i); finish(); } else { Toast.makeText(getApplicationContext(), "Server error", Toast.LENGTH_LONG).show(); } } catch (JSONException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "Json Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "Error: " + error.getMessage()); } }) { @Override protected Map<String, String>getParams() { Map<String, String>params = new HashMap<>(); params.put("secret key",SAFETY_NET_API_SECRET_KEY); params.put("user_response", MainActivity.this.user_response_token); return params; } }; Services.getInstance(this).addToRequestQueue(strReq); } }
When the ReCAPTCHA API executes the onSuccess() method, the user has successfully completed the CAPTCHA challenge.
Override the onSuccess() and onFailure() methods to handle both possible outcomes of the verification request task. In particular, if the API passes an instance of ApiException into onFailure(), you need to handle each possible status code that you can retrieve using getStatusCode().
Implementation of Google’s Re-CAPTCHA with Android Studio is very easy and very much useful, implementing it will give security from Bot’s.
The Major Advantages of Using CAPTCHA
By distinguishing between humans and automated computer programs, reCAPTCHA offers safety and security in a number of ways.
1) Protecting Registration Forms in Websites 2) Preventing Spam Comments 3) Making Online Shopping More Secure 4) Protecting Email Accounts
CONCLUSION
You now understand how to utilise the SafetyNet reCAPTCHA API to protect your Android app and back-end infrastructure from bot attacks.
You no longer have to be concerned about automated signups, screen scrapers, or bot-generated spam.