0

I'm currently struggling of how to correctly display the details from a table that is linked to another table in PHP. Right now my Android code have multiple fragment of displaying different details, and I can get to display those information from php into android code, but when I login the username, those details are shown differently.

Lets say I have profile fragment, balance fragment and record fragment. Right now when I log into the given username, those fragments are display other user details.

Additionally, in my PHP server, I have created 3 tables, each table are linked to one another. In my PHP code I create separate file for each table, because I follow some guide on the internet that can fetch data from php.

Table 1:

Table 1

Table 2

Table 2

This is balance.php code:

<?php

define('HOST','localhost');
define('USER','root');
define('PASS','');
define('DB','ips');

$con = mysqli_connect(HOST,USER,PASS,DB);

$sql = "select * from account_details";

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

$result = array();

$row = mysqli_fetch_assoc($res);

array_push($result,
array(
"Balance"=>$row['Balance'],
));

echo json_encode(array("result"=>$result));

mysqli_close($con);

?>

This is parking_record.php code

<?php

define('HOST','localhost');
define('USER','root');
define('PASS','');
define('DB','ips');

$con = mysqli_connect(HOST,USER,PASS,DB);

$sql = "select * from parking_record";

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

$result = array();

$row = mysqli_fetch_assoc($res);

array_push($result,
array(
"Parking_Amount"=>$row['Parking_Amount'],
"Date_Time"=>$row['Date_Time'],
));

echo json_encode(array("result"=>$result));

mysqli_close($con);

?>

Finally this is the profile_details.php code

<?php

define('HOST','localhost');
define('USER','root');
define('PASS','');
define('DB','ips');

$con = mysqli_connect(HOST,USER,PASS,DB);

$sql = "select * from profile_details";

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

$result = array();

$row = mysqli_fetch_assoc($res);

array_push($result,
array(
"FullName"=>$row['FullName'],
"DateOfBirth"=>$row['DateOfBirth'],
));

echo json_encode(array("result"=>$result));

mysqli_close($con);

?>

Android code

Balance.java

public class dri_balance extends ArrayAdapter<String> {
private String[] Acc_Balance;

private Activity context;

public dri_balance(Activity context, String[] Acc_Balance) {
    super(context, R.layout.fragment_balance, Acc_Balance);
    this.context = context;
    this.Acc_Balance = Acc_Balance;

}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = context.getLayoutInflater();
    View listViewItem = inflater.inflate(R.layout.fragment_balance, null, 
true);
    TextView tvBlnf = (TextView) listViewItem.findViewById(R.id.tvBlnf);

    tvBlnf.setText(Acc_Balance[position]);



    return listViewItem;
}
}

BalanceFragment.java

public class BalanceFragment extends Fragment implements 
View.OnClickListener {


public BalanceFragment() {
    // Required empty public constructor
}

public static final String JSON_URL = 
"http://192.168.1.2/json_balance_records.php";

private Button buttonGet;
private ListView listView;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
Bundle savedInstanceState) {
    // Inflate the layout for this fragment

    View rootView = inflater.inflate(R.layout.activity_listview, container, 
false);
    buttonGet = (Button) rootView.findViewById(R.id.buttonGet);
    buttonGet.setOnClickListener(this);

    listView = (ListView) rootView.findViewById(R.id.listView);

    return rootView;

    //return inflater.inflate(R.layout.fragment_profile, container, false);
}

private void sendRequest(){

    StringRequest stringRequest = new StringRequest(JSON_URL, new 
Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            showJSON(response);
        }
    },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {

Toast.makeText(getActivity().getApplicationContext(),error.getMessage(),
Toast.LENGTH_LONG).show();
                }
            });

    RequestQueue requestQueue = 
Volley.newRequestQueue(getActivity().getApplicationContext());
    requestQueue.add(stringRequest);
}

private void showJSON(String json){
    Dri_Balance pj = new Dri_Balance(json);
    pj.parseJSON();
    dri_balance cl = new dri_balance(getActivity(), 
Dri_Balance.Acc_Balance);
    listView.setAdapter(cl);
}

@Override
public void onClick(View v) {
    sendRequest();
}
}

parseJson Balance.java

public class Dri_Balance {

public static String[] Acc_Balance;


public static final String JSON_ARRAY = "result";
public static final String KEY_DriBalance = "Acc_Balance";


private JSONArray users = null;

private String json;

public Dri_Balance(String json){
    this.json = json;
}

public void parseJSON(){
    JSONObject jsonObject=null;
    try {
        jsonObject = new JSONObject(json);
        users = jsonObject.getJSONArray(JSON_ARRAY);

        Acc_Balance = new String[users.length()];


        for(int i=0;i<users.length();i++){
            JSONObject jo = users.getJSONObject(i);
            Acc_Balance[i] = jo.getString(KEY_DriBalance);

        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
}
}

How can show the correct data in Android?

I'm sorry for asking this too much, I did search for the internet but it didn't give me what I wanted. I am aware that I'm asking someone to do the homework for me but I am very new to Android and PHP.

New PHP code

I've edited the balance.php code (version 2):

define('HOST','localhost');
define('USER','root');
define('PASS','');
define('DB','ips');

$con = mysqli_connect(HOST,USER,PASS,DB);

$sql = "select Balance from account_details WHERE Username='$Username'";

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

$result = array();

$row = mysqli_fetch_assoc($res);

array_push($result,
array(
"Balance"=>$row['Balance'],
));

echo json_encode(array("result"=>$result));

mysqli_close($con);

?>

I try to run the php file it gave me null value

{
"result": [{
    "Balance": null
}]
}

Edited balance.php code (version 3)

<?php

define('HOST','localhost');
define('USER','root');
define('PASS','');
define('DB','ips');

$Username = $_GET["Username"];

$mysqli = mysqli_connect(HOST,USER,PASS,DB);

$stmt = $mysqli->prepare ("SELECT Balance from account_details WHERE 
Username=?");


$stmt->bind_param('s', $Username);
$stmt->execute();
$stmt->bind_result($Balance);

$rows = array();

while($stmt->fetch()) {
        array_push($rows, array('Balance'=>$Balance));
    }

$stmt->close();     

$mysqli->close();
echo json_encode($rows);

?>

Result

[{"Balance":"50.512"}]

OK, I have successfully joined the table in PHP and can get the result that I wanted. Right now I try to run my Android code, it crashes when I click to display the data, how do I correct the code?

halfer
  • 19,824
  • 17
  • 99
  • 186
lolol
  • 25
  • 1
  • 7
  • When your app connects to your PHP server, it looks like you are retrieving all records in each table in one go. Normally you have to send identifiers (like a username, hash and/or password) so the correct record can be returned. I wonder if fixing that would be a good place to start. – halfer Aug 06 '17 at 09:04
  • Pro-tips: (a) you do not need to store a "confirm password" in the database - that is merely a way of ensuring that a user has typed it correctly. When creating a record, ask for it twice, make sure they are the same, then store it once. (b) do not store passwords in plaintext, this makes your users vulnerable to secondary reuse attacks. I appreciate this is homework, and so you won't be using this for anything valuable, but it is a valuable to understand this is a vulnerability. – halfer Aug 06 '17 at 09:08
  • To obtain related records, you need a JSON endpoint that uses `JOIN` in its `SELECT` code. Search for "SQL JOIN related records" in a search engine. – halfer Aug 06 '17 at 09:09
  • @halfer im aware of the plain text password, at this moment is not the issue but right now i have added/edited the balance php file, but it gave me null value – lolol Aug 06 '17 at 15:04
  • OK, you have a SQL injection vulnerability in that file, so that needs to be fixed. If you are getting a null then it means you have a database error, or your search is not returning any records. Since this is a `GET` operation you can debug this in a browser, so I would suggest doing that first. Look up `http://localhost/balance.php?Username=myname`. However I can't see where `$Username` comes from - you need to read it from the query string using `$_GET['Username']`. – halfer Aug 06 '17 at 15:09
  • Once you fix that though, please urgently fix the new security hole - "it does not matter for this project" has a habit of slipping into real-world usage. – halfer Aug 06 '17 at 15:10
  • Read more here: http://stackoverflow.com/questions/60174 – halfer Aug 06 '17 at 15:12
  • @halfer is that the correct way to fix the SQL injection? Right now im able to get the correct result when i entered specified username. But my android code crash, how do i correct the android code? – lolol Aug 07 '17 at 07:10
  • Yes, version 3 of the balance PHP script looks good. I'd make column names and variable names lower-case, but that's just a matter of style. – halfer Aug 07 '17 at 08:58
  • As for the Android crash, we'd need to see a stack trace. Please edit that into the question. There will be an error in there that explains what went wrong. Make sure the URL is right - `json_balance_records.php` is not the same as `balance.php`, and of course it needs a query string of `?Username=xxx` at the end. You could also check your web server logs to see what URL your app is reaching. – halfer Aug 07 '17 at 09:00
  • @halfer Actually i fixed the crash just by adding the **echo json_encode(array("result"=>$rows));** because in my android code there is **public static final String JSON_ARRAY = "result";** so right now there is no crash. I did put correctly the URL **json_balance_records.php?Username=abc** and it show the information but how did i don't put the Username=abc just by login with the username and show the data? – lolol Aug 07 '17 at 09:48
  • I don't understand your question, sorry. The next thing you have to fix is to only answer queries that are authorised - presently you're providing private information in a JSON payload to anyone who wants it. Your next step is therefore to require a username and password for any per-user data. – halfer Aug 07 '17 at 10:13
  • @halfer I'm so sorry that i couldn't do this but how do i get the username and password for any per user data? – lolol Aug 07 '17 at 10:54
  • Something like this: `SELECT Balance from account_details WHERE Username=? AND Password=?`. You'll need to send in a password using `$_GET['Password']` again, and of course supply this in your Java call. If you want to do lookups in other tables, you will need to `JOIN` between that table and `account_details`. – halfer Aug 07 '17 at 13:29
  • @halfer Do you mean that i add the `SELECT Balance from account_details WHERE Username=? AND Password=?` in the php? If so i've added and can get the json output but i don't know how to correct the android code. I tried to put like this `http:192.168.1.2/json_balance_records.php?Username="` but still gave me empty value – lolol Aug 07 '17 at 14:03
  • `http://192.168.1.2/json_balance_records.php?Username=xxx&Password=yyy` - you missed out `//` and the password. Also you will need to use `https://` (i.e. a secure certificate) but save that until this is working first (that needs more server configuration). – halfer Aug 07 '17 at 15:20
  • @halfer I edited `http://192.168.1.2/json_balance_records.php?Username=abc&Pas‌​sword=abc123` it can display the data on my android app **but** only if i include the `Username=abc&Pas‌​sword=abc123` but what if i create another user for another details, the android app still showing me the previous user details. How can i not hardcoded the `Username` and `Password` and can display for that user? – lolol Aug 07 '17 at 15:43
  • OK, great! Your app needs to be able to ask the user for those details in a dialogue/settings box, and you'll need to store them in app storage (either SQLite or a file on the device). – halfer Aug 07 '17 at 15:51
  • @halfer How do i ask the user for those details and store them in storage? – lolol Aug 08 '17 at 03:58
  • That's too broad to answer here (and I don't develop for Android anyway). Break it down: how to make a settings dialog box? How to store data in an app? It will have all been done before, so search for it. – halfer Aug 08 '17 at 08:09
  • @halfer It's ok sir! You have been helping me a lot. Right now i will try to solve the problem on my own. Thanks. – lolol Aug 08 '17 at 09:16

1 Answers1

1

For completeness, and to summarise the comments conversation, here are the fixes required. The SQL queries in the original PHP-based JSON endpoints did not have a WHERE clause, so they would have delivered the whole table to the mobile app, and not the required record.

Also, there was no security details required in each endpoint request, so anyone on the internet would be able to retrieve any data, as long as they were in possession of a username. We added a password here, and suggested as an item for future work that the app include a credentials dialogue box, and appropriate local storage, so the user can identify themselves.

There was a SQL injection vulnerability, which was fixed with parameter binding in the MySQLi driver.

It has been noted that passwords should never be stored in plaintext. A hashing system that works in both Java and PHP would be required here.

Suggested improvements

You may want to think about how you could implement these things:

  • The connection should always be over HTTPS, and the app should refuse to connect if the endpoint is HTTP (secure certificates are free these days),
  • There should be a rate limiter, so that a user only gets a certain number of tries per minute, to prevent brute-force attacks,
  • There should be some IP blocking, so too many failed attempts from a certain IP locks it out for a period of time,
  • There should be a system to enforce minimum password length and complexity.
halfer
  • 19,824
  • 17
  • 99
  • 186