Защита php api для использования в приложении Android

Я новичок в разработке Android. Я использую android studio для разработки приложения. Что я сделал

  1. Создал DB с двумя таблицами в ней в MySQL.
  2. Создал два отдельных api's для методов GET и POST.
  3. Успешный доступ к обоим api's

Чего я достиг на данный момент

  1. Способный GET данные формируют GET api.
  2. Возможность POST данных с помощью api POST

Что мне теперь делать

Я хочу, чтобы мой API публиковался в Интернете, т.е. я хочу развернуть свои сервисы на сервере и получить к ним доступ. На данный момент я могу развернуть сервисы на сервере и получить к ним доступ.

Теперь я хочу, чтобы мои услуги (api's) были защищены. Для этого я искал много статей и нашел два пути.

  1. Используйте рамки yii. Кто-то сказал мне использовать его, потому что он автоматически защищал api's. Но я точно не знаю, так ли это или нет.
  2. Вручную обеспечить api's

Что касается пункта 1 фреймворк будет полезен, но он для меня новый, и потребуется время, чтобы с ним справиться, так как я уже создал веб-сервисы.

Для пункта 2 я получил некоторую информацию

  1. используя HMAC_SHA1
  2. ОБНАРУЖЕНИЕ МОБИЛЬНЫХ УСТРОЙСТВ, ИСПОЛЬЗУЮЩИХ PHP

Обе ссылки кажутся хорошими, но ссылка 1 не дает мне много информации об этом.

Очевидно, я хочу, чтобы мои оба api's

Теперь часть кода

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;

У меня есть user class из которого я получаю username и ID

JSONfunctions.java

Этот класс отвечает за получение данных из 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

Этот класс отвечает за метод POST

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("");
            }
        });
    }


}

Поскольку я новичок, я не знаю, что делать в php скрипте и что делать в моем коде Android :(. Было бы очень полезно, если бы кто-нибудь мог направить меня или дать мне учебник, которому я следую.

Любая помощь будет высоко оценен.

Ответы

Ответ 1

Чтобы защитить ваши API, вам нужен механизм для обнаружения того, что запрос на api сделан из надежного источника. Многие фреймворки поставляются с этой функцией по умолчанию.

Однако вы можете просто использовать JSON Web Tokens (jwt) с PHP, чтобы добавить авторизацию к вашим запросам api

Узнайте о аутентификации на основе токенов с на этой странице.

Ознакомьтесь с этим простым учебным пособием о том, как защитить ваши конечные точки PHP api с помощью JWT.

Если вам нужна еще больше безопасности, вы можете добавить сервис провайдера OAuth в свой API. прочитайте этот пост на как написать поставщика OAuth в PHP

Ответ 2

Единственный способ защитить ваш api - сделать ваш запрос на андроид уникальным. Выберите более конкретные данные из вашего приложения.

1 - получите уникальный идентификатор Android

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

И передайте его через ваш api Eg.

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

В вашем php запретите доступ, если нет уникального идентификатора Android (следует изменить с именем сложной переменной).Eg:

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

2 - Создайте свою собственную случайную переменную в приложении Android

Создайте свою собственную переменную, чтобы решить, что запрос поступает из вашего приложения. Например:

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

И также передайте это значение через свой запрос и подтвердите, когда дело доходит до php.

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

Отклонить запрос, если он не прошел или неправильно.

3 - Убедитесь, что запросы отправляются с Android

Я хочу рекомендовать использовать бесплатную лучшую библиотеку php http://mobiledetect.net/ Проверьте, не работает ли он от android и функция deny deny при неправильных нарушениях.

4 - Проверить запрос через строку User-Agent в PHP

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

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

И отрицать, если не от android в php.

5 - Запишите нападавших

Вам нужно отслеживать, нарушает ли кто-то один из ваших вышеперечисленных ценных бумаг. В настоящее время я использую ip-api.com для отслеживания злоумышленников.

вам нужно написать функцию deny с вставкой mysql. согласно ip-api, вы получите

1- атакующий ip
2- геолокация атакующих
3-ISP-атакующих

Таким образом, вы можете отрицать их статически.

Он собирается безопасно использовать ваш api от android и почти отказал в pc-запросах. Но три - это шанс разорвать ваше приложение с помощью обратной инженерии, например dex2jar или ShowJava и захватить вашу простую структуру данных. Как программист, выше функции и коды очень легки для них, и они будут работать с поддельными входами данных.

Таким образом, вы не должны писать программу со статическими значениями, такую ​​важную ссылку " http://192.168.100.9:8000/MobileApp/GET_DATA.php" как жестко закодированную, как в вашем приложении. Вы должны разделить данные, просто зашифровать и получить все ваши основные URL-адреса динамически, как описано выше, с помощью метода php/mysql api.

Если вы накрыли как 2-ступенчатую динамическую систему, очень мало шансов переломить вашу систему.
Я хочу сказать, что если вы используете для закрытой группы пользователей, вы должны использовать систему request- > approve для каждого пользователя для первой регистрации приложений, используя свой уникальный идентификатор и легко отказывать в доступе от других.

Ответ 3

защищать API-интерфейсы для доступа третьей стороной - это обширный домен, который будет обсуждаться. Наиболее часто используемый механизм защиты API-интерфейсов - это контроль доступа на основе токенов. Его можно реализовать разными способами.

1 вам нужно понять, как это работает. Обратитесь к этой ссылке и этой ссылке.

Затем попробуйте посмотреть, как его реализовать.

Рабочий пример реализации аутентификации на основе токенов с использованием "JSON Web Token (т.е. JWT)" в PHP и MySQL?

Если вам нужен более подробный пример, попробуйте эту ссылку.

Если вам нужна дополнительная информация, дайте мне знать.

Ответ 4

Используйте механизм управления сеансом, все описанные выше методы также говорят о том же. В простых словах используется зашифрованный закрытый ключ для обнаружения действительного источника

Ответ 5

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

Ответ 6

Здесь вы можете выбрать аутентификацию для PHP:

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

Я думаю, что Basic или Digest Auth (+ https://SSL с самоподписанным сертификатом) будет хорошим выбором для вас Rest-Service (PHP RESTful JSON API).

В Android-приложении я считаю, что лучше всего выбрать библиотеку RestClient:

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

(Я рекомендую вам сохранить весь исходный код только на одном языке -Java. Вы можете легко создать службу Java Rest и добавить Spring Аутентификация безопасности)

Ответ 7

Сначала добавьте зависимости в сборку gradle (приложение)
реализация 'com.mcxiaoke.volley: library: 1.0.16' Затем следуйте приведенному ниже коду:

 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);