【问题标题】:Securing php api to use in android application保护 php api 以在 android 应用程序中使用
【发布时间】:2017-07-15 04:09:27
【问题描述】:

我是安卓开发的新手。我正在使用android studio 开发应用程序。我做过的事情

  1. MySQL 中创建了一个包含两个表的DB
  2. GETPOST 方法创建了两个单独的 api's
  3. 成功访问api's

我现在的成就

  1. 能够从 GET api 获取 GET 数据。
  2. 能够使用 POST api POST 数据

我现在要做的事情

我希望我的 api 在线发布,即我想将我的服务部署到服务器并访问它们。此时我能够在服务器上部署服务并访问它们。

现在我希望我的服务 (api's) 得到保护。为此,我搜索了很多文章并找到了两种方法。

  1. 使用yii 框架。有人告诉我使用它,因为它会自动保护api's。但我不确定它是否有。
  2. 手动保护api's

至于1 点,该框架会有所帮助,但它对我来说是新的,需要时间来配合它,因为我已经创建了 Web 服务。

对于2点我得到了一些信息

  1. using HMAC_SHA1
  2. DETECTING MOBILE DEVICES USING 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,我从中得到usernameID

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 代码中做什么:(。如果有人可以指导我或给我一个教程,那将非常有帮助跟随。

任何帮助将不胜感激。

【问题讨论】:

标签: php android mysql api yii


【解决方案1】:

为了保护您的 API,您需要一种机制来检测对 api 的请求是否来自受信任的来源。许多框架默认带有此功能。

但是,您可以将 JSON Web Tokens (jwt) 与 PHP 一起使用来为您的 api 请求添加授权

this page 了解基于令牌的身份验证。

查看此 simple tutorial,了解如何使用 JWT 保护您的 PHP api 端点。

如果您需要更高的安全性,您可能希望将 OAuth 提供程序服务添加到您的 API。在how to write OAuth provider in PHP查看这篇文章

【讨论】:

    【解决方案2】:

    保护您的 api 的唯一方法是使您的 android 请求是唯一的。从您的应用中收集更具体的数据。

    1 - 获取 Android 唯一 ID -

    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 唯一 ID,则拒绝访问(应更改为复杂的变量名称)。例如:

    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函数。

    4 - 通过 PHP 中的 User-Agent 字符串验证请求

    $agent = $_SERVER['HTTP_USER_AGENT'];
    $agent=strtolower($agent);
    
    if (strpos($agent, 'android') !== false) {
    $os = 'Android';
    }
    

    如果不是来自 php 中的 android,则拒绝。

    5 - 记录攻击者

    您需要跟踪是否有人破坏了您的上述证券之一。 目前我正在使用ip-api.com 来跟踪攻击者。

    你需要用 mysql insert 编写拒绝函数。 根据ip-api,你会得到

    1- 攻击者的 ip
    2- 攻击者的地理位置
    3- 攻击者的 ISP

    所以你可以静态地拒绝它们。

    从 android 使用您的 api 将是安全的,并且几乎拒绝了 pc 请求。但是三个是通过逆向工程破坏您的应用程序的机会,例如 dex2jar 或 ShowJava 并获取您的简单数据结构。 作为程序员,上面的函数和代码对他们来说非常容易,他们会使用虚假的数据输入。

    因此,您不应编写具有静态值的程序,例如在您的应用程序中硬编码的重要链接“http://192.168.100.9:8000/MobileApp/GET_DATA.php”。 您应该像上面安全的 php/mysql api 方法一样拆分数据,简单加密并动态获取所有主要 url。

    如果您像 2 步动态系统一样覆盖,那么您的系统被破坏的机会非常少。
    我还有一个重要的事情要说,如果您用于封闭的用户组,您应该使用请求->批准系统为每个用户使用他们的唯一 ID 进行首次应用注册,并轻松拒绝其他人的访问。

    【讨论】:

      【解决方案3】:

      您可以在此处选择 PHP 身份验证:

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

      我认为 Basic 或 Digest Auth (+ https:// SSL with self signed certificate) 将是您的最佳选择 Rest-Service (PHP RESTful JSON API)。

      对于 Android 应用程序,我认为 RestClient 库的最佳选择是:

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

      (我建议您将所有源代码仅保留在一种语言中 -Java。您可以轻松创建 Java Rest Service 并添加 Spring Security 身份验证)

      【讨论】:

        【解决方案4】:

        保护 API 以供第 3 方访问是一个需要讨论的广阔领域。最常用的保护 API 的机制是基于令牌的访问控制。它可以通过多种方式实现。

        首先你需要了解它是如何工作的。请参考此link 和此link

        那就试试看如何实现吧。

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

        如果您需要更深入的示例,也可以试试这个link

        如果您需要更多信息,请告诉我。

        【讨论】:

          【解决方案5】:

          使用 Session 控制机制以上所有方法也都是一样的。简而言之,使用加密的私钥来检测有效来源

          【讨论】:

            【解决方案6】:

            首先在build gradle(app)中添加依赖
            实施 '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);
            

            【讨论】:

              【解决方案7】:

              我会简单地说, 如果您已经使用 PHP OPP,则无需使用任何框架。这对你来说会很耗时。 解决方案是:“像 laravel 和 yii 一样使用 remember_token 系统。在过滤之前对每个方法进行身份验证。” 如果您使用的是核心 PHP。在过滤 api 中的每个方法之前尝试相同的代码并包含它

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-09-19
                • 1970-01-01
                • 2020-05-29
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多