将查询从Android发送到远程服务器数据库的正确方法

时间:2017-08-29 15:34:11

标签: php android mysql database security

我在处理数据库方面不是很有经验。

我有一个Android应用程序,它应该从远程数据库服务器(MySQL)发送查询并从远程数据库服务器(MySQL)获取后续结果集。

我通过实际以JSON的形式将查询发送到服务器来完成此操作。然后,服务器脚本(PHP)将获取查询并执行它。然后将结果集再次解析为JSON并发送回Android应用程序。

我的PHP脚本

function run_query(mysqli $con, $query){
    $res=$con->query($query);
    return $res;
}

$reply = array();

if(isset($_POST['json'])) {
    require_once __DIR__.'/config.php';
    require_once __DIR__.'/DbController.php';
    $json = json_decode($_POST['json'], true);
    $query = $json['query'];
    $con = (new DbController())->connect(DBNAME);
    if(!$con){
        $reply['suc']=false;
        $reply['err_msg']=$con->error;
    }
    else{
        $res = run_query($con, $query);
        if(gettype($res)=="boolean"){
            $reply['query_reply']=$res;
            $reply['suc']=true;
            die(json_encode($reply));
        }
        $i=0;
        $reply['query_reply']= array();
        while($row = $res->fetch_row()){
            $reply['query_reply'][$i] = array();
            for($j=0;$j<sizeof($row);$j++)
                $reply['query_reply'][$i][$j]=$row[$j];
            $i++;
        }
        $reply['suc']=true;
    }
    echo json_encode($reply);
}

如您所见,'query'键包含MySQL服务器执行的整个查询字符串。

我的问题是 - 这种方式是否包含我不知道的任何安全(或其他)漏洞?另外,有更好的方法吗?

我的一个项目伙伴建议我将查询分成不同的部分(Like-&#34; query_type&#34;:&#34; SELECT&#34;,&#34; table_name&#34;:& #34; LOGIN_TABLE&#34;,&#34; where_args&#34;:&#34; WHERE x = x&#34;等等)并将其发送到服务器,然后在那里重建查询并执行。

但是,我不明白这会有什么帮助。任何建议将不胜感激。提前谢谢。

4 个答案:

答案 0 :(得分:6)

你的方法有很多问题。任何人都可以对您的协议进行反向工程并在SQL服务器上执行他们想要的任何查询。因此,您的数据不仅可供任何人阅读,也可由任何人修改。换句话说,你会被黑客入侵。

通常的做法是将蛋糕分成几层。这意味着使用输入参数类型,返回值和权限定义一个由明确且指定良好的方法构建的API。

这个API可以以你喜欢的任何方式实现,jsonrpc,SOAP,xmlrpc,你的选择,甚至HTTP GET到一个返回json的php脚本都可以工作。

最后一个选项有点笨重,但也很好,因为它允许你从你的网站内运行的javascript相同的api。无需拥有两个竞争API。

一个例子:

API get_user_profile(user_id INT);

INPUT:用户的整数id

RETURNS:此用户的表用户中的行,具体取决于他们的权限。

由于API在经过身份验证的会话中执行(使用cookie或其他),因此它知道用户发出请求的内容。因此,它会让用户看到他们的电话号码/电子邮件,但不会将这些字段返回给其他用户,除非他们是管理员(这是一个简单的权限示例,当然可能更复杂)

因此,每个操作都需要自己的API。有些很复杂,例如通用搜索。您可以通过使其行为或多或少像网站一样简化,而不是编写自己的迷你语言并使用参数来指定搜索选项。客户端将用户在搜索字段中键入的内容发送到服务器(如HTTP表单),服务器决定如何处理它。

显然,如果您的API的任何参数直接插入到SQL查询中,那么SQL注入意味着您也会被黑客入侵。因此,你需要做到正确,就像任何网站一样,暴露在邪恶互联网中的东西不断受到攻击。

将客户端视为浏览器,API将URL,表单,xmlhttprequest等称为服务器,将服务器称为PHP或其他任何服务器端语言。这基本上就是它。

答案 1 :(得分:1)

Rest api是android到远程服务器通信的最佳方法。 HttpClient,volley和Fast android网络库是一些简化其余api通信的库。 HttpClient太慢,因此不建议使用HttpClient。建议使用快速的Android网络库,因为它简单快速。

快速Android网络库的使用

Tutorial of fast android network library

答案 2 :(得分:0)

在客户端应用程序和远程数据库之间进行通信的最佳方式是使用RESTful API及其着名的HTTP请求GET, PUT, POST and DELETE。当您拥有REST API时,您可以使用同一个数据库拥有多个客户端应用,例如AndroidIOSJAVASCRIPT。它将由API_KEY保护,因此只有被授权进行查询或修改的请求才会被接受。
创建REST API的方法有很多种,因为您是PHP开发人员我会推荐Slim PHP framework,因为它的重量轻且易于使用。

答案 3 :(得分:0)

建议1:添加具有特定权限的mySql用户。或者向敏感表添加权限,例如具有其他用户信息的表...

建议2:为每个设备创建一个访问密钥,在每个请求中刷新它,并在响应时提供新的访问密钥,如果访问密钥无效则要求设备再次登录。如果登录成功,请为该设备提供新的访问密钥。

  • 保持一个老太太以时间间隔wises清除非活动设备
  • 在Android设备的SharedPreference中保留访问密钥

请检查YQL他们是否有同样的工作想法

尝试此类而不是volley

b= function(a,n){
    lst=sapply(1:(length(a)-n),function(t,a,n){a[t:(n+t-1)]},a,n,simplify = F)
    Reduce(function(x,y){rbind(x,y)},lst)
    }

<强> USAGE

        var app = angular.module('EntityApp', ['ngRoute', 'slickCarousel']);
    app.controller('EntityAppCntroller', function($scope, $http, $window) {
        if (localStorage.getItem('IsNewPinSet') != 1) {
            var getLocation = function() {
                if (navigator.geolocation) {
                    navigator.geolocation.getCurrentPosition(showPosition);
                } else {
                    alert("Geolocation is not supported by this browser.");
                }
            };
            getLocation();

            function showPosition(position) {
                var latitude;
                var longitude;
                latitude = position.coords.latitude;
                longitude = position.coords.longitude;
                localStorage.setItem('latitudeHome', latitude)
                localStorage.setItem('longitudeHome', longitude)
                var geocoder = new google.maps.Geocoder();
                var latlng = new google.maps.LatLng(latitude, longitude);
                geocoder.geocode({
                    'latLng': latlng
                }, function(results, status) {
                    if (status == google.maps.GeocoderStatus.OK) {
                        if (results[0]) {
                            for (var i = 0; i < results[0].address_components.length; i++) {
                                var types = results[0].address_components[i].types;
                                for (var typeIdx = 0; typeIdx < types.length; typeIdx++) {
                                    if (types[typeIdx] == 'postal_code') {
                                        var pin_all = results[0].address_components[i].short_name;
                                        localStorage.setItem('pincodehome', pin_all)
                                        $scope.pin_all = pin_all;
                                    }
                                }
                            }
                        } else {
                            console.log("No results found");
                        }
                    }
                });
            };
        }
        // $window.localStorage.getItem('pincodehome') is null
        // $window.localStorage.getItem('latitudeHome') is null
        // $window.localStorage.getItem('longitudeHome') is null
        //Common response in home page
        $http.get('someurl?pincode=' + localStorage.getItem('pincodehome') + '&lat=' + localStorage.getItem('latitudeHome') + '&lang=' + localStorage.getItem('longitudeHome'), {}).success(function(response) {
            $scope.Promotion = response.Promotion.Response;
        });
    });

使用了库

public class SyncToServer extends AsyncTask<String,String,String> {
Context context;
String url;
JSONObject jsonObjectToSend;
JSONArray jsonArrayToSend;
OnWebServiceListener onWebServiceListener;
ProgressDialog progressDialog;

/**
 * basic initializing, only use this contractor if you don't have anything to send.
 * @param context it can be null, if you don't want {@link ProgressDialog} pass it as null
 * @param url the url for data to be passed
 */
public SyncToServer(Context context,String url){
    this.context=context;
    this.url=url+"";
    Log.e("SyncToServer123",url+"");
    if(context!=null) {
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage("loading");
        progressDialog.setCancelable(false);
    }
        jsonObjectToSend=null;
}

/**
 * basic initializing, only use this contractor if you had anything to send.
 * @param context it can be null, if you don't want {@link ProgressDialog} pass it as null
 * @param url the url for data to be passed
 * @param jsonObject the {@link JSONObject} to pass server
 */
public SyncToServer(Context context,String url,JSONObject jsonObject){
    this.context=context;
    this.url=url;
    this.jsonObjectToSend=jsonObject;
    if(context!=null) {
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage("loading");
        progressDialog.setCancelable(false);
    }
}
/**
 * basic initializing, only use this contractor if you had anything to send.
 * @param context it can be null, if you don't want {@link ProgressDialog} pass it as null
 * @param url the url for data to be passed
 * @param jsonObject the {@link JSONArray} to pass server
 */
public SyncToServer(Context context,String url,JSONArray jsonObject){
    this.context=context;
    this.url=url;
    this.jsonArrayToSend=jsonObject;
    if(context!=null) {
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage("loading");
        progressDialog.setCancelable(false);
    }
}

/**
 * this method will register a callback, and start web service
 * @param onWebServiceListener this interface used to callback mechanism
 */
public void start(OnWebServiceListener onWebServiceListener){
    Log.i("SyncToServer123","start");
    this.onWebServiceListener=onWebServiceListener;
    this.execute();
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
    Log.i("SyncToServer123","init onPre");
    if(context!=null) {
        progressDialog.show();
    }
}

@Override
protected String doInBackground(String... strings) {
    HttpClient client = new DefaultHttpClient();
    Log.i("SyncToServer123","doIn");
            try {
                InputStream is;
                HttpPost post = new HttpPost(url);
                HttpResponse httpResponse;
                if (jsonObjectToSend != null) {
                    Log.i("SyncToServer123", jsonObjectToSend.toString());
                    StringEntity se = new StringEntity(jsonObjectToSend.toString());
                    Log.i("SyncToServer123", jsonObjectToSend.toString());
                    se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
                    post.setEntity(se);
                    post.setHeader("Accept", "application/json");
                    post.setHeader("Content-type", "application/json");
                    post.setHeader("connection", "close");
                    httpResponse = client.execute(post);
                }else if(jsonArrayToSend!=null){
                    Log.i("SyncToServer123", jsonArrayToSend.toString());
                    StringEntity se = new StringEntity(jsonArrayToSend.toString());
                    Log.i("SyncToServer123", jsonArrayToSend.toString());
                    se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
                    post.setEntity(se);
                    post.setHeader("Accept", "application/json");
                    post.setHeader("Content-type", "application/json");
                    post.setHeader("connection", "close");
                    httpResponse = client.execute(post);
                }else{
                    HttpGet httpGet=new HttpGet(url);
                    httpGet.setHeader("connection", "close");
                    httpResponse = client.execute(httpGet);
                }


                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();
                try {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(
                            is, "iso-8859-1"), 8);
                    StringBuilder sb = new StringBuilder();
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line + "");
                        System.out.println(line);
                        Log.i("SyncToServer123","PRE RESPONDS : "+line);
                    }
                    is.close();
                    String json = sb.toString();
                    JSONObject jObj;
                    jObj = new JSONObject(json);
                    Log.i("resultJson",json);

                    Log.i("SyncToServer123","RESPONDS : "+json);
                    reader.close();
                    httpEntity.consumeContent();

                    if(client != null && client.getConnectionManager() != null)
                    {
                        client.getConnectionManager().shutdown();
                    }

                    return json;
                } catch (Exception e) {
                    Log.i("SyncToServer123","Error "+e);
                    Log.e("Buffer Error", "Error converting result " + e.toString());
                }
                //customDbHelper.notifiSyncCompleted();
            } catch (Exception e) {
                Log.i("SyncToServer123","Error "+e);
                e.printStackTrace();
            }

    return null;
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);

    System.out.print("SyncToServer123:   "+s);

    if(s!=null){
        this.onWebServiceListener.onComplete(s);
    }else{
        this.onWebServiceListener.onError();
    }
    if(context!=null) {
        progressDialog.dismiss();
    }
}

/**
 * for callbacks the web service status,
 */
public interface OnWebServiceListener{
    /**
     * when service completed without any exception, including {@link JSONException}
     * @param result the responds given from server
     */
    void onComplete(String result);

    /**
     * if any exception occurred this method will call
     */
    void onError();
}
}