28

I am newbie to android development. I am using android studio for developing an application. Things i have done

  1. Created a DB with two tables in it in MySQL.
  2. Created two separate api's for both GET and POST methods.
  3. Successfully accessed both api's

What i have achieved for now

  1. Able to GET data form the GET api.
  2. Able to POST data using the POST api

What i have to do now

I want my api to publish online, i.e. I want to deploy my services into a server and access them. At this point i am able to deploy the services on the server and accessed them.

Now i want my services(api's) to be secured. For that i have searched many articles and found two ways.

  1. Use yii framework. Someone told me to use it because it automatically secured the api's. But i don't know for sure whether it do or not.
  2. Manually secure the api's

As for point 1 the framework will be helpful but it's new to me and it will take time to coop with it as i am already created the web services.

For point 2 i got some information

  1. using HMAC_SHA1
  2. DETECTING MOBILE DEVICES USING PHP

Both links seems to be good but link 1 doesn't gives me much info on that.

Obviously i want to secure my both api's

Now the code part

GET_DATA.php

require_once ('config.php');

$sql = "SELECT * FROM users";


$r = mysqli_query($con,$sql);

$result = array();

while($row = mysqli_fetch_array($r)){
array_push($result,array(
    'Id'=>$row['Id'],
    'Name'=>$row['Name']
));}

echo json_encode(array('users'=>$result));

POST_DATA.php

require_once ('config.php');

$return_arr = array();

$UserId=($_POST['UserId']);
$Latitude=($_POST['Latitude']);
$Longitude=($_POST['Longitude']);
$DateTime=($_POST['DateTime']);


$user_register_sql1 = "INSERT INTO `activity`(`Id`,`UserId`, `Latitude`,`Longitude`,`DateTime`) values (NULL,'".$UserId."','".$Latitude."','".$Longitude."','".$DateTime."')";
mysqli_query ($con,$user_register_sql1);
$row_array['errorcode1'] = 1;

I have a user class from which i am getting username and ID

JSONfunctions.java

This class is responsible for getting data from the api

 public static JSONObject getJSONfromURL(String url)
{

    String json = "";
    JSONObject jsonObject = null;
    try
    {
        HttpClient httpClientt = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse httpResponse = httpClientt.execute(httpGet);
        BufferedReader br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
        StringBuffer sb = new StringBuffer();
        String line = "";
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

        json = sb.toString();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    try
    {
        jsonObject = new JSONObject(json);
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return jsonObject;
}

PutUtility.Java

This class is responsible for POST method

public void setParam(String key, String value) {
    params.put(key, value);
}

public String postData(String Url) {

    StringBuilder sb = new StringBuilder();
    for (String key : params.keySet()) {
        String value = null;
        value = params.get(key);


        if (sb.length() > 0) {
            sb.append("&");
        }
        sb.append(key + "=" + value);
    }

    try {
        // Defined URL  where to send data

        URL url = new URL(Url);

        URLConnection conn = null;
        conn = url.openConnection();

        // Send POST data request
        httpConnection = (HttpURLConnection) conn;
        httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        httpConnection.setRequestMethod("POST");
        httpConnection.setDoInput(true);
        httpConnection.setDoOutput(true);
        OutputStreamWriter wr = null;

        wr = new OutputStreamWriter(conn.getOutputStream());
        wr.write(sb.toString());
        wr.flush();

        BufferedReader in = new BufferedReader(
                new InputStreamReader(httpConnection.getInputStream()));
        String inputLine;
        response = new StringBuffer();

        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();

    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    return response.toString();
}

MainActivity.java

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    _latitude = (TextView)findViewById(R.id.latitude);
    _longitude = (TextView)findViewById(R.id.longitude);
    btn_get_coordinates = (Button)findViewById(R.id.button);
    btn_save_data = (Button)findViewById(R.id.btn_save);   


    btn_save_data.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            if(UserId.toString()== "" || Latitude.toString() == "" || Longitude.toString() == "" || DateTime.toString() == "")
            {
                Toast.makeText(getApplicationContext(), "Data Not Saved !!!! Please select appropriate data to save", Toast.LENGTH_SHORT).show();
            }


            new ServiceLogin().execute(UserId, Latitude, Longitude, DateTime);

        }
    });

    // Download JSON file AsyncTask
    new DownloadJSON().execute();
}
    // Download JSON file AsyncTask
private class DownloadJSON extends AsyncTask<Void, Void, Void>
{

   @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(MainActivity.this);
        progressDialog.setMessage("Fetching Users....!");
        progressDialog.setCancelable(false);
        progressDialog.show();

    }

    @Override
    protected Void doInBackground(Void... params) {

        // Locate the Users Class
        users = new ArrayList<Users>();

        // Create an array to populate the spinner
        userList = new ArrayList<String>();
        // http://10.0.2.2:8000/MobileApp/index.php
        //http://10.0.2.2:8000/app/web/users/
        //http://192.168.100.8:8000/app/web/users/
        // JSON file URL address
        jsonObject = JSONfunctions.getJSONfromURL("http://192.168.100.9:8000/MobileApp/GET_DATA.php");

        try
        {
            JSONObject jobj = new JSONObject(jsonObject.toString());
            // Locate the NodeList name
            jsonArray = jobj.getJSONArray("users");

            for(int i=0; i<jsonArray.length(); i++)
            {
                jsonObject = jsonArray.getJSONObject(i);

                Users user = new Users();

                user.setId(jsonObject.optString("Id"));
                user.setName(jsonObject.optString("Name"));
                users.add(user);

                userList.add(jsonObject.optString("Name"));

            }
        } catch (JSONException e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }


        return null;
    }

    @Override
    protected void onPostExecute(Void args)
    {
        // Locate the spinner in activity_main.xml
        Spinner spinner = (Spinner)findViewById(R.id.spinner);

        // Spinner adapter
        spinner.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_spinner_dropdown_item, userList));

        // Spinner on item click listener

        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {


            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                textViewResult = (TextView)findViewById(R.id.textView);

                // Set the text followed by the position

                textViewResult.setText("Hi " + users.get(position).getName() + " your ID is " + users.get(position).getId());
                UserId = String.valueOf(users.get(position).getId());
                progressDialog.dismiss();
                _latitude.setText("");
                _longitude.setText("");
                Latitude = null;
                Longitude= null;

            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                textViewResult.setText("");
            }
        });
    }


}

As i am newbie, so i don't know what to do in php script and what to do in my android code :(. It would be very helpful if anyone can guide me or give me a tutorial that i follow.

Any help would be highly appreciated.

2

7 Answers 7

23
+25

To secure your APIs, you need a mechanism to detect that the request to the api is made from a trusted source. Many frameworks come with this feature by default.

However you can just use JSON Web Tokens (jwt) with PHP to add authorization to your api requests

Learn about token based authentication from this page.

Check out this simple tutorial on how to secure your PHP api endpoints with JWT.

If you need even more security you might want to add OAuth provider service to your API. check out this post on how to write OAuth provider in PHP

9

The only method to secure your api is making your android request to be unique .Collect more specific data from your app.

1 - Get Android Unique ID -

String UniqueID=Secure.getString(getActivity().getContentResolver(),Secure.ANDROID_ID);

And pass it through your api Eg .

http://192.168.100.9:8000/MobileApp/GET_DATA.php?yourvalue=something&id=UniqueID

In your php, deny access if there is no Android Unique ID(should change with complex variable name).Eg :

if($_REQUEST['UniqueID']=="" || strlen($_REQUEST['UniqueID'])<9){ //do something about abuse }else{ //your code }

2 - Create your own random variable in Android App

Create your own variable to decide to make sure the request comes from your app Eg:

Random r = new Random();
int i1 = r.nextInt(9999 - 1000) + 1000;

And also pass this value via your request and validate when it comes to php .

if($_REQUEST['r']>=1000 && $_REQUEST['r']<=9999){//}

Deny request if not passing or wrong value.

3 - Make sure requests come from Android

I want to recommend to use free best php library http://mobiledetect.net/ Check whether it is from android and write deny function on invalid abuses.

4 - Validate request via User-Agent string in PHP

$agent = $_SERVER['HTTP_USER_AGENT'];
$agent=strtolower($agent);

if (strpos($agent, 'android') !== false) {
$os = 'Android';
}

And deny if not from android in php.

5 - Record the attackers

You need to track if someone is breaking one of your above securities. Currently I am using ip-api.com to track attackers.

you need to write deny function with mysql insert. according to ip-api, you will get

1- Attackers' ip
2- Attackers' geolocation
3- Attackers' ISP

So you can deny them statically.

It is about to safe to use your api from android and almost denied pc requests. But three is a chance to break your app with reverse engineering like dex2jar or ShowJava and grab your simple data structure. As a programmer, above functions and codes are very easy for them and they will get in with fake data inputs.

So you should not write a program with static values, such important link "http://192.168.100.9:8000/MobileApp/GET_DATA.php" as hard coded as in your app. You should split data,simple encrypt and get all of your main urls dynamically as above secured php/mysql api method.

If you covered just like 2 step dynamic system, there is very very few chances to break in your system.
I've one important left to say, if you are using for closed group of users , you should use request->approve system for each user for first time app registration by using their unique ID and easily deny access from the others.

1
  • can a hacker see our post API Query using a MitM attack? Does that mean what user sending a request to the PHP API?
    – MDEV
    Commented Aug 2, 2022 at 13:56
1

You can choose you Authentication for PHP here:

http://pear.php.net/packages.php?catpid=1&catname=Authentication

I think that Basic or Digest Auth (+ https:// SSL with self signed certificate) will be good choose for you Rest-Service (PHP RESTful JSON API).

For Android application I think the best choose for RestClient library is:

http://square.github.io/retrofit/

(I recommend you to keep all source code in one Language only -Java. You can easy create Java Rest Service and add Spring Security Authentication)

0

secure the APIs in order to be accessed by a 3rd party is a vast domain to be discussed. Most used mechanism to secure APIs is token based access control. It can be implemented in many ways.

1st you need understand how it works. Refer this link and this link.

Then try to look at how to implement it.

Working example of implementing 'Token Based Authentication' using 'JSON Web Token (i.e. JWT)' in PHP and MySQL?

If you need more in-depth example try this link as well.

If you need more information let me know.

0

Use Session control mechanism all the above methods are also talking for the same. In Simple words use encrypted private key to detect the valid source

0

First add the dependencies in build gradle (app)
implementation 'com.mcxiaoke.volley:library:1.0.16' Then follow the below code:

 final ProgressDialog loading = ProgressDialog.show(getActivity(), "", "Please wait...", false, false);
        StringRequest stringRequest = new StringRequest(Request.Method.POST, ServerLinks.TOTAL_COUNT_URL, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                loading.dismiss();
                try {
                    JSONObject jsonObject = new JSONObject(response);

                    String status = jsonObject.getString("status");

                    if (status.equals("success")) {
                        String data = jsonObject.getString("data");

                        JSONObject jsonObject1 = new JSONObject(data);
                        String male = jsonObject1.getString("male");
                        String female = jsonObject1.getString("female");


                    } else {
                        // no_data_found.setVisibility(View.VISIBLE);
                        Toast.makeText(getActivity(), "No Data Found", Toast.LENGTH_SHORT).show();
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }//onResponse()
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                loading.dismiss();
                //Toast.makeText(getActivity(), "Check Your Internet Connection", Toast.LENGTH_SHORT).show();
            }
        });
        int socketTimeout = 30000; // 30 seconds. You can change it
        RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);

        stringRequest.setRetryPolicy(policy);
        RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
        requestQueue.add(stringRequest);
0

I will simply say, If you already using PHP OPP, then no need to go with any framework. It will be time consuming for you. Solution is: "Use remember_token system as like laravel and yii. Authenticate to each method before filter." If you are using Core PHP. Try same code and include it before filter each method in your api

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.